zoukankan      html  css  js  c++  java
  • 【ZOJ2760】How Many Shortest Path

    How Many Shortest Path

    标签: 网络流


    描述

    Given a weighted directed graph, we define the shortest path as the path who has the smallest length among all the path connecting the source vertex to the target vertex. And if two path is said to be non-overlapping, it means that the two path has no common edge. So, given a weighted directed graph, a source vertex and a target vertex, we are interested in how many non-overlapping shortest path could we find out at most.

    Input
    Input consists of multiple test cases. The first line of each test case, there is an integer number N (1<=N<=100), which is the number of the vertices. Then follows an N * N matrix, represents the directed graph. Each element of the matrix is either non-negative integer, denotes the length of the edge, or -1, which means there is no edge. At the last, the test case ends with two integer numbers S and T (0<=S, T<=N-1), that is, the starting and ending points. Process to the end of the file.

    Output
    For each test case, output one line, the number of the the non-overlapping shortest path that we can find at most, or "inf" (without quote), if the starting point meets with the ending.

    Sample Input
    4
    0 1 1 -1
    -1 0 1 1
    -1 -1 0 1
    -1 -1 -1 0
    0 3
    5
    0 1 1 -1 -1
    -1 0 1 1 -1
    -1 -1 0 1 -1
    -1 -1 -1 0 1
    -1 -1 -1 -1 0
    0 4

    Sample Output
    2
    1


    扯淡

    看见大佬们都在虐题好紧张啊,于是跑过来被题虐。


    题意

    给你一张图,求从起点到终点最多有多少条最短路径(互不重合)。


    题解

    • 本题光凭最短路是无法解决的,我们还需要建立网络流模型来解决。
    • 对于每一条边,这些最短路只会经过一次。所以,我们只需要把所有属于最短路上面的边都找出来,在新的网络流模型中连这样一条边。跑一遍网络流,问题就解决了。
    • 如何检查边是否在最短路上呢?你先跑一遍最短路,然后对于每一条边,只需要检查dist[起点][i]+a[i][j]+dist[j][终点]是否等于dist[起点][终点]就行了。

    PS:

    • 自己到自己的边不一定为0......造数据的人怎么想的。
    • 我打了两遍这道题,第一遍用spfa写的很丑,还T了,于是又写了一遍floyd,然后......也T了。仔细一看题目发现我很傻逼,没有看到如果起点和终点一样,就输出"inf",然后两份代码改完之后都A了。这说明题目中的细节有时候也是很重要的。

    Code

    两份代码都粘上来

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    using namespace std;
    #define ll long long
    #define REP(i,a,b) for(register int i=(a),_end_=(b);i<=_end_;i++)
    #define DREP(i,a,b) for(register int i=(a),_end_=(b);i>=_end_;i--)
    #define EREP(i,a) for(register int i=start[(a)];i;i=e[i].next)
    inline int read()
    {
    	int sum=0,p=1;char ch=getchar();
    	while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
    	if(ch=='-')p=-1,ch=getchar();
    	while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
    	return sum*p;
    }
    
    const int maxn=220;
    
    int dist[maxn][maxn],a[maxn][maxn],n;
    
    struct node {
    	int v,next,w;
    };
    node e[maxn*maxn];
    int start[maxn],cnt;
    
    void addedge(int u,int v,int w)
    {
    	e[++cnt]={v,start[u],w};
    	start[u]=cnt;
    }
    
    void Addedge(int u,int v,int w)
    {
    	addedge(u,v,w);
    	addedge(v,u,0);
    }
    
    int st,en,S,T;
    
    bool init()
    {
    	cnt=1;
    	memset(start,0,sizeof(start));
    	REP(i,1,n)
    	{
    		REP(j,1,n)
    		{
    			dist[i][j]=a[i][j]=read();
    			if(a[i][j]==-1)dist[i][j]=a[i][j]=1<<27;
    			if(i==j)dist[i][j]=a[i][j]=0;
    		}
    	}
    	REP(k,1,n)
    	{
    		REP(i,1,n)
    		{
    			REP(j,1,n)
    			{
    				dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
    			}
    		}
    	}
    	st=read()+1;en=read()+1;
    	S=0;T=n+1;
    	if(st==en)
    	{
    		cout<<"inf"<<endl;
    		return false;
    	}
    	Addedge(S,st,1<<30);Addedge(en,T,1<<30);
    	REP(i,1,n)
    	{
    		REP(j,1,n)
    		{
    			if(i==j)continue;
    			if(a[i][j]==(1<<27))continue;
    			if(dist[st][en]==dist[st][i]+dist[j][en]+a[i][j])
    				Addedge(i,j,1);
    		}
    	}
    	return true;
    }
    
    int lev[maxn],cur[maxn];
    
    bool bfs()
    {
    	queue<int>q;
    	REP(i,0,n+1)lev[i]=0;
    	q.push(S);
    	lev[S]=1;
    	do{
    		int u=q.front();q.pop();
    		EREP(i,u)
    		{
    			int v=e[i].v;
    			if(!lev[v] && e[i].w)
    			{
    				lev[v]=lev[u]+1;
    				q.push(v);
    				if(v==T)return true;
    			}
    		}
    	}while(!q.empty());
    	return false;
    }
    
    int dfs(int u,int flow)
    {
    	if(u==T)return flow;
    	int tag=0;
    	for(int &i=cur[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(lev[v]==lev[u]+1 && e[i].w)
    		{
    			int c=dfs(v,min(flow-tag,e[i].w));
    			e[i].w-=c;
    			e[i^1].w+=c;
    			tag+=c;
    			if(tag==flow)return tag;
    		}
    	}
    	return tag;
    }
    
    void doing()
    {
    	int ans=0;
    	while(bfs())
    	{
    		REP(i,0,n+1)cur[i]=start[i];
    		ans+=dfs(S,1<<30);
    	}
    	cout<<ans<<endl;
    }
    
    int main()
    {
    	while(scanf("%d",&n)==1)
    	{
    		if(init())
    		doing();
    	}
    	return 0;
    }
    
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define ll long long
    #define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
    #define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
    #define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
    inline int read()
    {
    	int sum=0,p=1;char ch=getchar();
    	while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
    	if(ch=='-')p=-1,ch=getchar();
    	while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
    	return sum*p;
    }
    
    int n,S=0,T=0;
    const int maxn=500;
    struct node {
    	int v,next,w;
    };
    node e[maxn*maxn];
    node ee[maxn*maxn];
    node eee[maxn*maxn];
    int cnt,start[maxn],a[maxn][maxn];
    int cntt,startt[maxn];
    int cnttt,starttt[maxn];
    void addedge(int u,int v,int w)
    {
    	e[++cnt]={v,start[u],w};
    	start[u]=cnt;
    }
    
    void addedge1(int u,int v,int w)
    {
    	ee[++cntt]={v,startt[u],w};
    	startt[u]=cntt;
    }
    
    void addedge2(int u,int v,int w)
    {
    	eee[++cnttt]={v,starttt[u],w};
    	starttt[u]=cnttt;
    }
    
    void Addedge(int u,int v,int w)
    {
    	addedge(u,v,w);
    	addedge(v,u,0);
    }
    
    int flag=1;
    
    void init()
    {
    	flag=1;
    	memset(startt,0,sizeof(startt));
    	cntt=0;
    	cnt=1;
    	cnttt=0;
    	memset(start,0,sizeof(start));
    	memset(starttt,0,sizeof(starttt));
    	REP(i,1,n)
    	{
    		REP(j,1,n)
    		{
    			a[i][j]=read();
    		}
    	}
    	REP(i,1,n)
    	{
    		REP(j,i+1,n)
    		{
    			if(a[i][j]!=-1)addedge1(i,j,a[i][j]),addedge2(j,i,a[i][j]);
    			if(a[j][i]!=-1)addedge1(j,i,a[j][i]),addedge2(i,j,a[j][i]);
    		}
    	}
    	S=read()+1,T=read()+1;
    	if(S==T)
    	{
    		cout<<"inf"<<endl;
    		flag=0;
    	}
    	Addedge(0,S,1<<30);
    	Addedge(T,n+1,1<<30);
    }
    
    int dist[maxn],vis[maxn];
    #include<queue>
    bool spfa()
    {
    	REP(i,1,n)dist[i]=1<<30;
    	REP(i,1,n)vis[i]=0;
    	dist[S]=0;
    	vis[S]=1;
    	queue<int>q;
    	q.push(S);
    	do{
    		int u=q.front();q.pop();
    		//EREP(i,u)
    		for(int i=startt[u];i;i=ee[i].next)
    		{
    			int v=ee[i].v;
    			if(dist[v]>dist[u]+ee[i].w)
    			{
    				dist[v]=dist[u]+ee[i].w;
    				if(!vis[v])
    				{
    					vis[v]=1;
    					q.push(v);
    				}
    			}
    		}
    		vis[u]=0;
    	}while(!q.empty());
    	if(dist[T]==(1<<30))return false;
    	return true;
    }
    
    int dist1[maxn];
    
    void spfa1()
    {
    	REP(i,1,n)dist1[i]=1<<30;
    	REP(i,1,n)vis[i]=0;
    	dist1[S]=0;
    	vis[S]=1;
    	queue<int>q;
    	q.push(S);
    	do{
    		int u=q.front();q.pop();
    		for(int i=starttt[u];i;i=eee[i].next)
    		{
    			int v=eee[i].v;
    			if(dist1[v]>dist1[u]+eee[i].w)
    			{
    				dist1[v]=dist1[u]+eee[i].w;
    				if(!vis[v])
    				{
    					vis[v]=1;
    					q.push(v);
    				}
    			}
    		}
    		vis[u]=0;
    	}while(!q.empty());
    }
    
    int lev[maxn],ans;
    
    
    bool bfs()
    {
    	queue<int>q;
    	REP(i,0,n+1)lev[i]=0;
    	lev[S]=1;
    	q.push(S);
    	do{
    		int u=q.front();q.pop();
    		EREP(i,u)
    		{
    			int v=e[i].v;
    			if(e[i].w && !lev[v])
    			{
    				lev[v]=lev[u]+1;
    				q.push(v);
    				if(v==T)return true;
    			}
    		}
    	}while(!q.empty());
    	return false;
    }
    
    int cur[maxn];
    
    int dfs(int u,int flow)
    {
    	int c=0,tag=0;
    	if(u==T)return flow;
    	for(int &i=cur[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(e[i].w && lev[v]==lev[u]+1)
    		{
    			c=dfs(v,min(flow-tag,e[i].w));
    			e[i].w-=c;
    			e[i^1].w+=c;
    			tag+=c;
    			if(tag==flow)return tag;
    		}
    	}
    	return tag;
    }
    
    
    void doing()
    {
    	if(!spfa())
    	{
    		cout<<"0"<<endl;
    		return;
    	}
    	swap(S,T);
    	spfa1();
    	swap(S,T);
    	REP(i,1,n)
    	{
    		for(int j=startt[i];j;j=ee[j].next)
    		{
    			int v=ee[j].v;
    			if(dist[i]+ee[j].w+dist1[v]==dist[T])Addedge(i,v,1);
    		}
    	}
    	S=0;T=n+1;
    	ans=0;
    	while(bfs())
    	{
    		REP(i,0,n+1)cur[i]=start[i];
    		ans+=dfs(S,1<<30);
    	}
    	cout<<ans<<endl;
    }
    
    
    int main()
    {
    	while(scanf("%d",&n)==1)
    	{
    		init();
    		if(flag)
    		doing();
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    ftp 下载最近一小时的文件
    hdu4767 Bell——求第n项贝尔数
    Uva11762 Race to 1——有向无环图&&记忆化搜索
    P3232 [HNOI2013]游走——无向连通图&&高斯消元
    Random Walk——高斯消元法
    B君的历史——复数乘法&&爆搜
    复数快速幂【模板】
    UVa11542Squre——异或方程组&&高斯消元法
    UVa10828 Back to Kernighan-Ritchie——概率转移&&高斯消元法
    高斯消元法【模板】
  • 原文地址:https://www.cnblogs.com/gzy-cjoier/p/7282191.html
Copyright © 2011-2022 走看看