题目:BZOJ-1797
题解:关于最小割可以去这里看一下,对话形式的解释,讲的挺清楚的。
对于本题:
1.最小路劲的切断方案:就是指最小割,包不包括这条边就是指最小割的方案中有没有一个包含这条边
2.通络流大小==最小割大小,一个网络流值对应多种最小割方案
3.Dinic算法跑完后求出网络流值,会把图中所有的满流的边删掉,最小割一定是由满流的边组成,但不是任意的几个满流的边都能4.组成最小割
4.Dinic算法跑完后剩下的残图,残图中有多个连通块,如果对于一条边他的起终点在两个不同的连通块中,那么就说明这条边是满流,构成了最大流,那么他可以参与构成最小割,如果这条边的起点在s所在连通块,终点在t所在连通块内,那么就说明这条边是必须被删除的满流边,是必须参与构成最小割的
(相当于:①对于任意一条满流边(u,v),(u,v)能够出现在某个最小割集中,当且仅当id[u]!=id[v];
②对于任意一条满流边(u,v),(u,v)必定出现在最小割集中,当且仅当id[u]==id[s]且id[v]==id[t]。)
那么这个题目就可以先跑一遍Dinic求出残图,然后再在残图中跑Tarjan,把联通块找出来,记录节点所在联通块编号,然后再按边查询这道题就解决了~
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<stack>
#define N 100005
#define M 100005
#define INF 0x7fffffff
using namespace std;
int n,m,s,t,c,tot,num;
int head[N],cur[N],dfn[N],low[N],deep[N],belong[N];
bool vis[N];
struct ljh
{
int next,to,w,from;
}e[2*M];
stack<int>ss;
inline void add(int x,int y,int z)
{
e[c].next=head[x];
e[c].from=x;
e[c].to=y;
e[c].w=z;
head[x]=c++;
}
inline void init()
{
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(belong,0,sizeof(belong));
tot=0;
c=0;
num=0;
}
bool bfs(int s,int t)
{
queue<int>q;
memset(deep,0,sizeof(deep));
deep[s]=1;
q.push(s);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i!=-1;i=e[i].next)
{
int nex=e[i].to;
if(e[i].w!=0&&deep[nex]==0)
{
deep[nex]=deep[x]+1;
q.push(nex);
}
}
}
return deep[t]!=0;
}
int dfs(int x,int t,int maxflow)
{
if(x==t)return maxflow;
int ans=0;
for(int i=cur[x];i!=-1;i=e[i].next)
{
int nex=e[i].to;
if(deep[nex]!=deep[x]+1||ans>=maxflow||e[i].w<=0)continue;
cur[x]=i;
int k=dfs(nex,t,min(e[i].w,maxflow-ans));
e[i].w-=k;
e[i^1].w+=k;
ans+=k;
}
if(ans==0)deep[x]=-2;
return ans;
}
void Dinic(int s,int t)
{
while(bfs(s,t))
{
memcpy(cur,head,sizeof(head));
dfs(s,t,INF);
}
}
void Tarjan(int x)
{
low[x]=dfn[x]=++tot;
ss.push(x);
vis[x]=1;
for(int i=head[x];i!=-1;i=e[i].next)
{
if(e[i].w)//判断一下,这条边必须是残留的边才可以更新联通块
{
int v=e[i].to;
if(!dfn[v])
{
Tarjan(v);
low[x]=min(low[x],low[v]);
}
else if(vis[v]==1)low[x]=min(low[x],dfn[v]);
}
}
if(low[x]==dfn[x])//这里没注意,找bug找到自闭
{
int nex;
num++;
do
{
nex=ss.top();
ss.pop();
vis[nex]=0;
belong[nex]=num;
}while(!ss.empty()&&nex!=x);
}
return;
}
int main()
{
while(~scanf("%d%d%d%d",&n,&m,&s,&t))
{
init();
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,0);
}
Dinic(s,t);
for(int i=1;i<=n;i++)
if(!dfn[i])
Tarjan(i);
for(int i=0;i<c;i+=2)
{
if(e[i].w>0)printf("0 0\n");//说明那条边根本就没走
else
{
if(belong[e[i].from]!=belong[e[i].to])printf("1 ");
else printf("0 ");
if(belong[e[i].from]==belong[s]&&belong[e[i].to]==belong[t])printf("1\n");
else printf("0\n");
}
}
}
}