题目:ZOJ-2532
题意:CIA公司想采用新技术升级网络,在实验测试阶段,他们想升级其中的一段网络以便观察新技术在多大的长度上提升网络的性能,你作为实习生的任务是调查那一段网络能提高CIA总部的宽带。
题解:一种比较好想到的思路就是枚举每条边,将容量增加1,看这样最大流和之前的是否相等,但这样复杂度太高。
于是不妨换种思路,假设现在满流了,我们会考虑增加哪些边的容量呢?显然是满流的边。那么增加了这条边的容量之后,总流量在什么条件下会增加呢?产生一条新的增广路(不知道这个这个名词用得是否恰当,大家意会吧……)。
搞清楚上面的问题之后就会得到一个复杂度较好的算法,枚举做完最大流之后的每条边u->v,如果这条边满流,并且存在S到u的增广路以及v到T的增广路,那么增加这条边的容量就会增大总流量。判断S到u有无增广路可以先用dfs预处理一下,从S点开始只沿非满流的边走,能够到达某个位置就说明S到这个位置存在增广路。至于判断v到T有无增广路也是类似的。
代码:
#include<bits/stdc++.h>
#define N 100005
#define INF 0x7fffffff
using namespace std;
int n,m,l,sum,s,t,c;
int head[N],deep[N],cur[N],ans[N];
bool viss[N],vist[N];
struct ljh
{
int next,to,w,from;
}e[N*2],a[N*2];
inline add(int x,int y,int z)
{
e[c].next=head[x];
e[c].w=z;
e[c].to=y;
e[c].from=x;
head[x]=c++;
}
bool bfs(int s,int t)
{
memset(deep,0,sizeof(deep));
deep[s]=1;
queue<int>q;
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(deep[nex]==0&&e[i].w>0)
{
deep[nex]=deep[x]+1;
q.push(nex);
}
}
}
return deep[t];
}
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;
}
int Dinic(int s,int t)
{
int ans=0;
while(bfs(s,t))
{
memcpy(cur,head,sizeof(head));
ans+=dfs(s,t,INF);
}
return ans;
}
void DFS(int x,bool *vis,int k)
{
vis[x]=1;
for(int i=head[x];i!=-1;i=e[i].next)
{
int nex=e[i].to;
if(!vis[nex]&&e[i^k].w>0)
{
vis[nex]=1;
DFS(nex,vis,k);
}
}
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&l)&&n!=0)
{
bool flag=0;
c=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=l;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,0);
}
s=n+m+1;
t=0;
for(int i=1;i<=n;i++)
{
add(s,i,INF);
add(i,s,0);
}
sum=Dinic(s,t);
memset(viss,0,sizeof(viss));
memset(vist,0,sizeof(vist));
DFS(s,viss,0);
DFS(t,vist,1);
int num=0;
for(int i=1;i<=l;i++)
{
if(viss[e[(i-1)*2].from]==1&&vist[e[(i-1)*2].to]==1&&e[(i-1)*2].w==0)
{
ans[++num]=i;
}
}
for(int i=1;i<=num;i++)printf("%d ",ans[i]);
printf("\n");
}
return 0;
}