这题还挺有意思的……呃……我的意思是,反正我不会。。。。。。。
做法嘛,先求最小割是肯定的了,然后就是很坑爹的结论题。
边(u,v)能出现在最小割集中当且仅当(u,v)为满流且在残量网络里u,v不属于同一个强连通分量。
边(u,v)必定出现在最小割集中当且仅当(u,v)为满流且在残量网络中u与s在同一强连通分量且v与t在同一强连通分量。
证明什么的,画个图试试?
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<stack> using namespace std; const int inf=1e9; struct Edge{int to,next,v;}e[200005]; int head[4005],d[4005],cnt=1; int sccno[4005],dfs_clock,scc_cnt,lowlink[4005],pre[4005]; stack<int>s; void ins(int u,int v,int w){ cnt++;e[cnt].to=v;e[cnt].next=head[u];e[cnt].v=w;head[u]=cnt; } void insert(int u,int v,int w){ ins(u,v,w);ins(v,u,0); } bool bfs(int s,int t){ memset(d,-1,sizeof(d)); d[s]=0;queue<int>q;q.push(s); while(!q.empty()){ int u=q.front();q.pop(); for(int i=head[u];i;i=e[i].next) if(e[i].v&&d[e[i].to]==-1){ d[e[i].to]=d[u]+1; q.push(e[i].to); } } return d[t]!=-1; } int dfs(int x,int f,int t){ if(x==t)return f; int flow=0,w; for(int i=head[x];i;i=e[i].next) if(e[i].v&&d[e[i].to]==d[x]+1){ w=f-flow; w=dfs(e[i].to,min(e[i].v,w),t); e[i].v-=w;e[i^1].v+=w;flow+=w; if(flow==f)return f; } if(!flow)d[x]=-1; return flow; } int dinic(int s,int t){int flow=0;while(bfs(s,t))flow+=dfs(s,inf,t);return flow;} void tarjan(int u){ pre[u]=lowlink[u]=++dfs_clock; s.push(u); for(int i=head[u];i;i=e[i].next) if(e[i].v){ int v=e[i].to; if(!pre[v]){ tarjan(v); lowlink[u]=min(lowlink[u],lowlink[v]); }else if(!sccno[v]) lowlink[u]=min(lowlink[u],pre[v]); } if(lowlink[u]==pre[u]){ scc_cnt++; while(true){ int x=s.top();s.pop(); sccno[x]=scc_cnt; if(x==u)break; } } } int main(){ int n,m,s,t; scanf("%d%d%d%d",&n,&m,&s,&t); int u,v,c; for(int i=1;i<=m;i++){ scanf("%d%d%d",&u,&v,&c); insert(u,v,c); } dinic(s,t); for(int i=1;i<=n;i++)if(!pre[i])tarjan(i); for(int i=1;i<=m;i++) if(e[i<<1].v) printf("0 0\n"); else{ int u=e[i<<1].to,v=e[i<<1|1].to; printf("%d %d\n",sccno[u]!=sccno[v],sccno[s]==sccno[v]&&sccno[t]==sccno[u]); } return 0; }