USACO 4.4 追查坏牛奶
好题呀quq
第一问根据最大流最小割定理,求出最大流就是最小割的值
第二问就十分麻烦了,USACO还有一个加强版:求割边的割集,这就比较棘手了
有一个比较投机取巧的方法:将所有的边权乘以一个大质数并加一,此时的答案ans与原来的答案pre相比,有如下关系
ans = temp * mod + k
k即为最小割的边数
但这样的方法是过不去USACO的,我们得从最大流的本质去考虑
考虑到:对于一个割C(S,T),所有从S到T的边必然满流(否则残余网络上还有增广路,可以继续更新最大流)所以满流的边**可能**成为割边,但不一定全都是(反例参照题目样例) 但是,如果一条边是割边,割掉这条边后,原图的流量一定减去它的流量(如果不是这样的话,说明可以用其他的边代替这个边,此边就没有必要割了)
所以,我们选出图中所有满流边,每次试着去割去一条,看其是否是割边(依照上文的方法)即可
这里给出第一种方法的代码,第二种方法调好后我会马上上发
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<queue> #include<vector> using namespace std; #define int long long const int maxn = 10005; const int maxm = 2e5 + 5; const int inf = 999999999; const int mod = 1007; inline int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (ans *= 10) += ch - '0'; ch = getchar(); } return ans * op; } struct egde { int to,cost,next,other; }e[maxm]; int fir[maxn],alloc; void adde(int u,int v,int w) { e[++alloc].next = fir[u]; fir[u] = alloc; e[alloc].to = v; e[alloc].cost = w * mod + 1; e[alloc].other = alloc + 1; swap(u,v); e[++alloc].next = fir[u]; fir[u] = alloc; e[alloc].to = v; e[alloc].cost = 0; e[alloc].other = alloc - 1; } int n,m,s,t; int cnt,ans; bool vis[maxn]; int dep[maxn]; bool bfs(int s,int t) { memset(dep,0,sizeof(dep)); queue<int> q; dep[s] = 1; q.push(s); while(q.size()) { int u = q.front(); q.pop(); for(int i = fir[u];i;i = e[i].next) { int v = e[i].to,c = e[i].cost; if(c > 0 && dep[v] == 0 && vis[i] == 0) { dep[v] = dep[u] + 1; q.push(v); } } } //for(int i = 1;i <= n;i++) printf("%d %d\n",i,dep[i]); if(dep[t]) return 1; else return 0; } int find(int u,int f)//在u点,要解决值为f的流量 { //printf("%d %d\n",u,f); if(u == t) return f; int curflow = 0,t = 0; for(int i = fir[u];i;i = e[i].next) { int v = e[i].to,c = e[i].cost; if(c > 0 && dep[v] == dep[u] + 1 && curflow < f && vis[i] == 0) { t = find(v,min(c,f - curflow)); curflow += t; e[i].cost -= t; e[e[i].other].cost += t; } } return curflow; } main() { n = read(),m = read(); for(int i = 1;i <= m;i++) { int u = read(),v = read(),w = read(); adde(u,v,w); } s = 1,t = n; while(bfs(s,t)) ans += find(s,inf); printf("%d ",ans / mod); printf("%d",ans % mod); }