ZOJ - 2532 - Internship(网络流)

题目: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;
}	

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值