「USACO4.4」追查壞牛奶Pollutant Control 解題報告
阿新 • • 發佈:2019-01-02
題面
求最小割,並且在最小割的情況下求出最少要刪去幾條邊
思路:
當然是最小割咯!
就是後一問不大好求
那怎麼辦呢? 似乎很複雜的樣子
或許我們要在模板裡改比較困難
那麼我們就想辦法在邊上做學問
比如我們可不可以把邊的容量全部加1呢?
有人問:這樣最小割不就是不一樣了嗎?
但是細想一下可以發現:其實在加1的情況下,原來的最小割確實變了,但是增大了多少就等於最少要刪去的邊數
因為對於每條邊,容量又多了一個1,在最小割的前提下,肯定是刪去越少的邊數的情況更優
舉個栗子:
強迫症,這圖畫了我半天
Code:
#include<bits/stdc++.h> #define INF 0x7f7f7f7f #define M 1010 #define N 50 using namespace std; struct node{ int to,cap; int nxt; node(int a,int b):to(a),cap(b){ } node(){ } }b[M<<1]; int head[N],deep[N]; int n,m,S,T,t=1,Maxflow,Ans; int read() { int s=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { s=(s<<1)+(s<<3)+c-'0'; c=getchar(); } return s; } void add(int x,int y,int cap) { b[++t]=node(y,cap); b[t].nxt=head[x]; head[x]=t; b[++t]=node(x,0); b[t].nxt=head[y]; head[y]=t; return; } bool BFS() { int i,cur; int to,cap; queue<int>p; memset(deep,0,sizeof(deep)); deep[S]=1;p.push(S); while(!p.empty()) { cur=p.front();p.pop(); for(i=head[cur];i;i=b[i].nxt) { to=b[i].to;cap=b[i].cap; if(cap&&!deep[to]) { deep[to]=deep[cur]+1; p.push(to); if(to==T) return 1; } } } return 0; } int Dinic(int k,int flow) { if(k==T) return flow; int i,to,cap,res,rest=flow; for(i=head[k];i&&rest;i=b[i].nxt) { to=b[i].to;cap=b[i].cap; if(cap&&deep[to]==deep[k]+1) { res=Dinic(to,min(rest,cap)); if(!res) deep[to]=0; b[i].cap-=res; b[i^1].cap+=res; rest-=res; } } return flow-rest; } int main() { int i,flow; int x,y,cap; n=read();m=read(); S=1;T=n; for(i=1;i<=m;i++) { x=read();y=read();cap=read(); add(x,y,cap); } while(BFS())//先求最小割 while((flow=Dinic(S,INF))) Maxflow+=flow; while(BFS()) while((flow=Dinic(S,INF))) Maxflow+=flow; for(i=2;i<=t;i+=2)//改變邊 b[i].cap+=b[i^1].cap+1,b[i^1].cap=0;//初始正邊並1,反邊還是賦0 while(BFS())//再跑一次 while((flow=Dinic(S,INF))) Ans+=flow; printf("%d %d",Maxflow,Ans-Maxflow);//一次性輸出 return 0; }