您的位置:首页 > 其它

ZOJ 2532 Internship

2010-12-29 20:49 507 查看
找关键割边,即如果只是增加这条的边容量后,能增加最大流,那么,这条边满足3条性质:

1.满流,如果不满流,增大容量也没用

2.残余网络中,源点可以到达该边的头节点

3.残余网络中,该边的尾节点可以到达汇点

即通过这条扩容的边后可以重新找到一条增广路径

做法跟POJ 3204相同,先跑一次最大流,然后分别从源点和汇点开始,在残余网络中做两次DFS

但这道题按从小到大的顺序需要输出关键割边在输入数据中的id,即第几天边,我一开始用一个数组记录的,但最后WA了,用了别人的方法,现在网络中增加segment边,这样,第i条segment边在数组中的下标就为(i-1)*2,这样就过了,所以数据中应该有重边

代码:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<memory.h>
using namespace std;
const int MAX=105;
const int inf=1<<30;
struct node
{
int u,v,c,next;
}g[10000];
int dis[MAX],cur[MAX],num[MAX],adj[MAX],pre[MAX];
int edge[MAX][MAX],res[MAX],vs[MAX],vt[MAX];
int s,t,vn,e;
void add(int u,int v,int c)
{
g[e].u=u; g[e].v=v; g[e].c=c; g[e].next=adj[u]; adj[u]=e++;
g[e].u=v; g[e].v=u; g[e].c=0; g[e].next=adj[v]; adj[v]=e++;
}
void dfs1(int x)
{
vs[x]=1;
for(int i=adj[x];i!=-1;i=g[i].next)
{
if(g[i].c&&!vs[g[i].v])
dfs1(g[i].v);
}
}
void dfs2(int x)//从汇点开始反向DFS
{
vt[x]=1;
for(int i=adj[x];i!=-1;i=g[i].next)
{
if(g[i^1].c&&!vt[g[i].v])//i^1为i的反向边,找能从g[i].v->x的边
dfs2(g[i].v);
}
}
int sap()
{
int i,u,v,flow=0,aug=inf,flag;
for(i=0;i<=vn;i++)
{
dis[i]=num[i]=0;
cur[i]=adj[i];
}
pre[s]=u=s;
num[0]=vn;
while(dis[s]<vn)
{
flag=0;
for(i=cur[u];i!=-1;i=g[i].next)
{
v=g[i].v;
if(g[i].c&&dis[u]==dis[v]+1)
{
flag=1;
pre[v]=u;
cur[u]=i;
aug=min(aug,g[i].c);
u=v;
if(u==t)
{
flow+=aug;
while(u!=s)
{
u=pre[u];
g[cur[u]].c-=aug;
g[cur[u]^1].c+=aug;
}
aug=inf;
}
break;
}
}
if(flag)
continue;
if(--num[dis[u]]==0)
break;
for(dis[u]=vn,i=adj[u];i!=-1;i=g[i].next)
{
v=g[i].v;
if(g[i].c&&dis[v]<dis[u])
{
dis[u]=dis[v];
cur[u]=i;
}
}
dis[u]++;
num[dis[u]]++;
u=pre[u];
}
return flow;
}
int main()
{
int i,m,n,l,a,b,w,cnt;
while(scanf("%d%d%d",&n,&m,&l)!=EOF)
{
if(!n)
break;
memset(adj,-1,sizeof(adj));
//memset(edge,0,sizeof(edge));
e=0;
s=n+m+1;
t=0;
vn=s+1;
for(i=1;i<=l;i++)
{
scanf("%d%d%d",&a,&b,&w);
//edge[a][b]=edge[b][a]=i;
add(a,b,w);
}
for(i=1;i<=n;i++)
add(s,i,inf);
sap();
memset(vs,0,sizeof(vs));
memset(vt,0,sizeof(vt));
dfs1(s);
dfs2(t);
//memset(res,0,sizeof(res));
cnt=0;
for(i=0;i<e;i+=2)
{
if(g[i].c==0&&vs[g[i].u]&&vt[g[i].v])
{
if(cnt==0)
printf("%d",i/2+1);
else
printf(" %d",i/2+1);
cnt++;
//res[cnt++]=edge[g[i].u][g[i].v];
}
}
/*sort(res,res+cnt);
for(i=0;i<cnt;i++)
{
if(i)
printf(" %d",res[i]);
else
printf("%d",res[i]);
}*/
if(!cnt)
printf("/n");
printf("/n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: