zoj 2532(Internship )找割边
题目大意就是给你n个城市,m个中转站,以及l条道路,l条道路描述了n个城市(编号为1到n),m个中转站(编号为n+1到n+m)和总中心(视为编号为0的点)的边关系,然后问你增加哪条边的容量可以增加总中心接受到的数据量。
首先设总中心0为超级汇点et(因为它接受信息),然后设个超级源点st(N+M+1),超级源点就是发出数据的点,因为题目说了每个城市可以看作有无限的数据要发送,所以将每个城市和源点连起来,容量为inf。然后很明显这题就是要找割边,我的理解是割边就是流量满了即残留已经为0的边,并且从st可以到这条边的一个点,从et可以到这条边的另外一个点,那么给这条边增加容量就可以 增大最大流了。做法就是先跑个dinic,目的是得到在最大流情况下的残量网络,然后在此基础上从st往et方向dfs,标记从st点出发能到的点,接着从et往st方向dfs,标记从et点出发能到的点,最后遍历每个正边判断一下是否是割边即可。
这题我因为没有给en初始化,每次交都Segmentation Fault,心累,最后还是逐个语句排除才找到的bug
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define inf 0x3f3f3f3f
struct edge
{
int u,v,cap,nxt;
}e[5500];
int head[500],depth[500],vis1[500],vis2[500],cur[500],ans[5000],que[500];
int n,m,l,st,et,en;
void addedge(int u,int v,int c)
{
e[en].u=u;
e[en].v=v;
e[en].cap=c;
e[en].nxt=head[u];
head[u]=en++;
e[en].u=v;
e[en].v=u;
e[en].cap=0;
e[en].nxt=head[v];
head[v]=en++;
}
bool bfs()
{
int fron,rear;
fron=rear=0;
for(int i=et;i<=st;i++)
depth[i]=0;
depth[st]=1;
que[rear++]=st;
while(fron!=rear)
{
int u=que[fron++];
for(int i=head[u];i!=-1;i=e[i].nxt)
{
if(e[i].cap&&!depth[e[i].v])
{
depth[e[i].v]=depth[u]+1;
que[rear++]=e[i].v;
}
}
}
return depth[et]!=0;
}
int dfs(int u,int f)
{
if(u==et) return f;
for(int&i=cur[u];i!=-1;i=e[i].nxt)
{
if((depth[e[i].v]==depth[u]+1)&&e[i].cap)
{
int ff=dfs(e[i].v,min(f,e[i].cap));
if(ff>0)
{
e[i].cap-=ff;
e[i^1].cap+=ff;
return ff;
}
}
}
return 0;
}
void dinic()
{
int maxflow=0;
while(bfs())
{
for(int i=et;i<=st;i++)
cur[i]=head[i];
int tmp;
while(tmp=dfs(st,inf))
maxflow+=tmp;
}
}
void dfs1(int u)
{
vis1[u]=1;
for(int i=head[u];i!=-1;i=e[i].nxt)
{
int v=e[i].v;
if(!vis1[v]&&e[i].cap)
dfs1(v);
}
}
void dfs2(int u)
{
vis2[u]=1;
for(int i=head[u];i!=-1;i=e[i].nxt)
{
if(!vis2[e[i^1].u]&&e[i^1].cap)
dfs2(e[i^1].u);
}
}
int main()
{
std::ios::sync_with_stdio(false);
while(1)
{
cin>>n;
if(!n) break;
cin>>m>>l;
et=0;
st=n+m+1;
for(int i=et;i<=st;i++)
head[i]=-1;
en=0;
for(int i=1;i<=l;i++)//建图
{
int uu,vv,cc;
cin>>uu>>vv>>cc;
addedge(uu,vv,cc);
}
for(int i=1;i<=n;i++)//将源点和每个城市相连,不用对汇点操作,因为汇点才输入的时候就操作完了
addedge(st,i,inf);
dinic();
memset(vis1,0,sizeof(vis1));
memset(vis2,0,sizeof(vis2));
dfs1(st);
dfs2(et);
int k=0;
for(int i=0;i<en;i+=2)
{
int u=e[i].u;
int v=e[i].v;
int c=e[i].cap;
if((vis1[u]==1)&&(vis2[v]==1)&&(c==0))
ans[k++]=i/2+1;
}
if(k==0)
cout<<endl;
else
{
cout<<ans[0];
for(int i=1;i<k;i++)
cout<<" "<<ans[i];
cout<<endl;
}
}
return 0;
}