您的位置:首页 > 理论基础 > 计算机网络

HDU 5294 Tricks Device 残余网络(最短路+最大流)**

2015-08-14 15:29 661 查看
题意:一个人抓另一个人,有一个地图(无向),纯洁的Wu抓到Zhang的条件是:只有走最短路才能抓到他。纯洁Wu在1点,Zhang在n点。

问你Zhang要最少切断几条路可以使纯洁Wu抓不到他,还有一个问题就是Zhang最多切了多少条边使得纯洁Wu还有机会抓到他。

做法:首先看第一个问题,要求的就是从点1到点n,有几条没有边重复的最短路(这里不是说找完了最短路把它删掉,再找最短路,这样的话所有的可以通向终点的都可以认为是最短路,而是长度同为首次找到的起点连接到终点的路径),再来看第二个问题,其实最多可以切的路段,即保留source到sink的最短路中路段最短的路径,其它的都可以切掉。

因为留下的这个路径满足纯洁Wu抓到Zhang的条件。

实施过程:首先我们可以通过单源最短路算法求出以点1为源点的所有最短路(dijstra,spfa...),此时新建一个原图满足dis[v]=dis[u]+w[u->v]的图,此时的图里面存的路径只要它可以走到终点,那么这条路径就是可以让纯洁Wu找到Zhang。




如果就如上图所示Zhang最少要切掉2条,如果将其想象成网络流,当每一条边的容流量都是1的时候,显然有公共边的路径只能跑一次,这样在新图中运用最大流算法,求解即可。

注意:在求最短路的时候,定义一个路段数的数组L[p],即从源点走到p点,所经过的最小的路段数,一定要理解它的更新。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define it __int64
#define inf 0x7fffffff
using namespace std;
const int N=2000+5;
const int M=60000+5;
int n,m;
struct node
{
	int v,next;
	int w;
}e[M*2];
struct nodee
{
	int v,next;
	int flow;
}ne[M*2];
int head
,cnt,nhead
,ncnt,tiao;
int s,t;
void Init()
{
	memset(head,-1,sizeof(head));
	memset(nhead,-1,sizeof(nhead));
	cnt=ncnt=0;
}
void add(int a,int b,int c)
{
	e[cnt].v=b;
	e[cnt].w=c;
	e[cnt].next=head[a];
	head[a]=cnt++;
}
void nadd(int a,int b,int c)
{
	ne[ncnt].v=b;
	ne[ncnt].flow=c;
	ne[ncnt].next=nhead[a];
	nhead[a]=ncnt++;
	
	ne[ncnt].v=a;
	ne[ncnt].flow=0;
	ne[ncnt].next=nhead[b];
	nhead[b]=ncnt++;
} 
void Input()
{
	for(int i=1;i<=m;i++)
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		if(a==b) continue;
		add(a,b,c);
		add(b,a,c);
	}
	s=1;t=n;
}
class Dinic
{
	public:
		void spfa()
		{
			queue<int>q;
			while(!q.empty()) q.pop();
			for(int i=1;i<=n;i++)
			{
				dis[i]=inf;
				vis[i]=0;
				l[i]=inf;
			}
			dis[s]=0;
			l[s]=0;
			vis[s]=1;
			q.push(s);
			while(!q.empty())
			{
				int u=q.front();
				q.pop();
				vis[u]=0;
				for(int i=head[u];i+1;i=e[i].next)
				{
					int v=e[i].v;
					if(dis[v]>dis[u]+e[i].w)
					{
						dis[v]=dis[u]+e[i].w;
						l[v]=l[u]+1;
						if(!vis[v])
						{
							vis[v]=1;
							q.push(v);
						}
					}
					else if(dis[v]==dis[u]+e[i].w)
					{
						if(l[v]>l[u]+1)
						{
						    l[v]=l[u]+1;
						    if(!vis[v])
						    {
						    	vis[v]=1;
							    q.push(v);
						    }
						}
					}
				}
			}
			tiao=l[t];
		}
		void build_map()
		{
			for(int i=1;i<=n;i++)
			{
				for(int j=head[i];j+1;j=e[j].next)
				{
					int v=e[j].v;
					if(dis[v]==dis[i]+e[j].w)
					{
						nadd(i,v,1);
					}
				}
			}
		}
		int spath()
		{
			queue<int>q;
			while(!q.empty()) q.pop();
			memset(ndis,-1,sizeof(ndis));
			ndis[s]=0;
			q.push(s);
			while(!q.empty())
			{
				int u=q.front();
				q.pop();
				for(int i=nhead[u];i+1;i=ne[i].next)
				{
					int v=ne[i].v;
					if(ndis[v]==-1&&ne[i].flow>0)
					{
						ndis[v]=ndis[u]+1;
					    q.push(v);
					}
				}
			}
			return ndis[t]!=-1;
		}
		int Min(int a,int b)
		{
			if(a<b) return a;
			return b;
		}
		int dfs(int u,int flow)
		{
			int cost=0;
			if(u==t) return flow;
			for(int i=nhead[u];i+1;i=ne[i].next)
			{
				int v=ne[i].v;
				if(ndis[v]==ndis[u]+1&&ne[i].flow>0)
				{
					int min=dfs(v,Min(flow-cost,ne[i].flow));
					if(min>0)
					{
						ne[i].flow-=min;
						ne[i^1].flow+=min;
						cost+=min;
						if(cost==flow) break;
					}
					else ndis[v]=-1;
				}
			}
			return cost;
		}
		int solve()
		{
			int res=0;
			while(spath())
			{
				res+=dfs(s,inf);
			}
			return res;
		}
	private:
		it dis
;
		int vis
,l
,ndis
;
}dinic;
void Output()
{
	dinic.spfa();
	dinic.build_map();
	printf("%d %d\n",dinic.solve(),m-tiao);
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		Init();
		Input();
		Output();
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: