先跑一遍最大流,然后对残量网络(即所有没有满流的边)进行tarjan缩点。
- 能成为最小割的边一定满流:因为最小割不可能割一半的边;
- 连接s、t所在联通块的满流边一定在最小割里:如果不割掉这条边的话,就能再次从s到t增广
连接两个不同联通块的满流边可能在最小割里:新图(即缩点后只有满流边的图)的任意一条s、t割都是最小割,所以可以任取割的方案
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=50005,M=100005,inf=1e9; int n,m,s,t,h[N],cnt=1,le[N],dfn[N],low[N],tot,bl[N],con,st[N],top; bool in[N]; struct qwe { int ne,no,to,va; }e[M<<1]; int read() { int f=1,r=0; char p=getchar(); while(p>‘9‘||p<‘0‘) { if(p==‘-‘) f=-1; p=getchar(); } while(p>=‘0‘&&p<=‘9‘) { r=r*10+p-48; p=getchar(); } return r*f; } void add(int u,int v,int w) { cnt++; e[cnt].ne=h[u]; e[cnt].no=u; e[cnt].to=v; e[cnt].va=w; h[u]=cnt; } void ins(int u,int v,int w) { add(u,v,w); add(v,u,0); } bool bfs() { queue<int>q; memset(le,0,sizeof(le)); le[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=h[u];i;i=e[i].ne) if(e[i].va>0&&!le[e[i].to]) { le[e[i].to]=le[u]+1; q.push(e[i].to); } } return le[t]; } int dfs(int u,int f) { if(u==t||!f) return f; int us=0; for(int i=h[u];i&&us<f;i=e[i].ne) if(e[i].va>0&&le[e[i].to]==le[u]+1) { int t=dfs(e[i].to,min(e[i].va,f-us)); e[i].va-=t; e[i^1].va+=t; us+=t; } if(!us) le[u]=0; return us; } void dinic() { while(bfs()) dfs(s,inf); } void tarjan(int u) { dfn[u]=low[u]=++tot; in[st[++top]=u]=1; for(int i=h[u];i;i=e[i].ne) if(e[i].va)//保证在残量网络上 { if(!dfn[e[i].to]) { tarjan(e[i].to); low[u]=min(low[u],low[e[i].to]); } else if(in[e[i].to]) low[u]=min(low[u],dfn[e[i].to]); } if(low[u]==dfn[u]) { con++; while(st[top]!=u) { bl[st[top]]=con; in[st[top--]]=0; } bl[st[top]]=con; in[st[top--]]=0; } } int main() { n=read(),m=read(),s=read(),t=read(); for(int i=1;i<=m;i++) { int u=read(),v=read(),w=read(); ins(u,v,w); } dinic(); for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);/cout<<"ok"<<endl; for(int i=2;i<=cnt;i+=2) { if(e[i].va) puts("0 0"); else { if(bl[e[i].no]!=bl[e[i].to]) printf("1 "); else printf("0 "); if(bl[e[i].no]==bl[s]&&bl[e[i].to]==bl[t]) puts("1"); else puts("0"); } } return 0; }