bzoj1797 [Ahoi2009]Mincut 最小割
我们首先跑一遍最大流。
可以发现如果一个流没跑或者没有跑满,他肯定不再最小割中。如果没跑,那么去掉它之后新图的最小割依然等于最大流,所以割他没有用,而没有跑满的边可以看作是一个满了的边和一个空的边,割了就是浪费了他多余的流量。
那么如果一个边跑满了呢?
对于残留网络缩点,如果$id[u]!=id[v]$,那么可能选到这条边。
如果 $id[u]==id[S]且id[v]==id[T]$ ,那么一定选这条边。
现在感性理解了,理性证明坑待填。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <cmath> 6 #include <queue> 7 #define N 4005 8 #define inf 0x7fffffff 9 using namespace std; 10 int n,m,S,T; 11 int e=2,head[N]; 12 struct edge{ 13 int u,v,f,next; 14 }ed[120050]; 15 void add(int u,int v,int f){ 16 ed[e].u=u;ed[e].v=v;ed[e].f=f; 17 ed[e].next=head[u];head[u]=e++; 18 ed[e].u=v;ed[e].v=u;ed[e].f=0; 19 ed[e].next=head[v];head[v]=e++; 20 } 21 int dep[N]; 22 bool bfs(){ 23 memset(dep,0,sizeof dep); 24 queue<int> Q; 25 Q.push(S);dep[S]=1; 26 while(!Q.empty()){ 27 int x=Q.front();Q.pop(); 28 for(int i=head[x];i;i=ed[i].next){ 29 if(ed[i].f&&!dep[ed[i].v]){ 30 dep[ed[i].v]=dep[x]+1; 31 if(ed[i].v==T)return 1; 32 Q.push(ed[i].v); 33 } 34 } 35 } 36 return 0; 37 } 38 int dfs(int x,int f){ 39 if(x==T||!f)return f; 40 int ans=0; 41 for(int i=head[x];i;i=ed[i].next){ 42 if(ed[i].f&&dep[ed[i].v]==dep[x]+1){ 43 int nxt=dfs(ed[i].v,min(f,ed[i].f)); 44 ans+=nxt;f-=nxt;ed[i].f-=nxt;ed[i^1].f+=nxt; 45 } 46 if(!f)break; 47 } 48 if(!ans)dep[x]=-1; 49 return ans; 50 } 51 int dinic(){ 52 int ans=0; 53 while(bfs())ans+=dfs(S,inf); 54 return ans; 55 } 56 int dfn[N],low[N],top,q[N],id[N],tot; 57 bool bo[N]; 58 void tarjan(int x){ 59 dfn[x]=low[x]=++top; 60 q[top]=x;bo[x]=1; 61 for(int i=head[x];i;i=ed[i].next){ 62 if(ed[i].f){ 63 int v=ed[i].v; 64 if(!dfn[v]){ 65 tarjan(v); 66 low[x]=min(low[x],low[v]); 67 } 68 else if(bo[v]){ 69 low[x]=min(low[x],dfn[v]); 70 } 71 } 72 } 73 if(low[x]==dfn[x]){ 74 int y;tot++; 75 do{ 76 y=q[top--]; 77 id[y]=tot; 78 bo[y]=0; 79 }while(y!=x); 80 } 81 } 82 int main(){ 83 scanf("%d%d%d%d",&n,&m,&S,&T); 84 for(int i=1,u,v,f;i<=m;i++){ 85 scanf("%d%d%d",&u,&v,&f); 86 add(u,v,f); 87 } 88 dinic(); 89 for(int i=1;i<=n;i++) 90 if(!dfn[i])tarjan(i); 91 for(int i=2;i<e;i+=2){ 92 if(!ed[i].f){ 93 if(id[ed[i].u]!=id[ed[i].v])printf("1 "); 94 else printf("0 "); 95 if(id[ed[i].u]==id[S]&&id[ed[i].v]==id[T])puts("1"); 96 else puts("0"); 97 } 98 else puts("0 0"); 99 } 100 return 0; 101 }
人生如梦亦如幻 朝如晨露暮如霞。