P1674题解

  1. 1. P1674 [USACO05FEB] Secret Milking Machine G 题解
    1. 1.1. 题目大意
    2. 1.2. 建模
    3. 1.3. 代码

P1674 [USACO05FEB] Secret Milking Machine G 题解

题目大意

给出一张无向图,图上每条边只允许经过一次,给出经过图的次数 ,找到经过的最长边中长度最小的长度。

建模

很明显费用流建模,每条边权值为长度,流量为一,直接连边,注意建双向边。那这个最长的边的长度怎么着呢?其实很简单,只要将更新 的条件由 改为 即可。同理,最小费用也改为 为汇点)。当增广到的流量大于 时,直接跳出搜索,输出答案即可。代码用的是 Dijkstra 找增广路,本来还在想势能怎么更新,写着写着发现没必要用势能,就直接放个阉割版 Dijkstra 上去了,好像也不用开 longlong。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int M = 5e5 + 10;
const int inf = 0x7fffffff;
struct edge {
int u, v, c, val, nxt;
edge(int u = 0, int v = 0, int c = 0, int val = 0, int nxt = 0) : u(u), v(v), c(c), val(val), nxt(nxt) {}
} e[M];
int head[N];
int cnt = 1;
int now[N];
void ADD(int u, int v, int c, int val) {
cnt++;
e[cnt] = edge(u, v, c, val, head[u]);
head[u] = cnt;
}
void add_edge(int u, int v, int c, int val) {
ADD(u, v, c, val);
ADD(v, u, 0, -val);
}

int n, m, T;
int s, t;
struct Node {
int name, dis;
bool operator<(const Node &a) const {
return dis > a.dis;
}
};
int dis[N];
bool vis[N];
int h[N]; //完全没有用到的势能
int pro[N];
int flow[N];
int mn, mx;
bool dj() {
for (int i = 1; i <= n; i++) flow[i] = dis[i] = inf;
for (int i = 1; i <= n; i++) pro[i] = -1;
memcpy(now, head, sizeof head);
dis[1] = 0;
priority_queue<Node>q;
q.push({1, dis[1]});
while (q.size()) {
int u = q.top().name;
int d = q.top().dis;
q.pop();
if (d > dis[u]) continue;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
int c = e[i].c;
if (!c) continue;
int val = e[i].val;
if (dis[v] > max(dis[u], val)) {
dis[v] = max(dis[u], val); //注意这里的长度转移
flow[v] = min(flow[u], c);
pro[v] = i;
q.push({v, dis[v]});
}
}
}
return dis[t] == inf;
}
void maxflow() {
while (!dj()) {
mx += flow[t];
mn = max(mn, dis[t]);
if (mx >= T) {
cout << mn;
exit(0);
}
int u = t;
while (u != s) {
e[pro[u]].c -= flow[t];
e[pro[u] ^ 1].c += flow[t];
u = e[pro[u]].u;
}
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m >> T;
s = 1, t = n;
for (int i = 1; i <= m; i++) {
int a, b, l;
cin >> a >> b >> l;
add_edge(a, b, 1, l); //朴实无华的建图
add_edge(b, a, 1, l); //记得反边也建上
}
maxflow();
}

第一次写题解,如有什么错误或者不理解的地方,欢迎留言。