您的位置:首页 > 其它

poj 3613 Cow Relays 经L边的最短路

2014-11-24 18:20 363 查看
题意:

求无向图s,t点间经过L条边的最短路。

思路:

矩阵连乘求图中任意两点间的最短路不经常用,因为复杂度是N^3logN的,但这种算法对最短路径经过的路径数的描述却非常清晰,尤其当需经过路径L比较大而顶点数N比较小的时候,N^3logL就比较可观了,求最短路径的特殊矩阵乘法满足结合律,可以幂乘加速。很有意思的是:把两个mul函数中的k循环放到i,j之外后整个算法就变成了倍增floyd算法(倍增floyd每次不用min(g[i][j],g[i][k]+G[k][j])更新g[i][j]有别于floyd算法),结果复杂度都一样。理解倍增floyd有助于理解floyd中动态规划的特点。

代码:

//poj 3613
//sepNINE
#include <iostream>
#include <map>
using namespace std;
const int maxN=512;
int g[maxN][maxN];
int ans[maxN][maxN];
int tmp[maxN][maxN];
map<int,int> mymap;
int n;
void mul1()
{
	int i,j,k;
	for(i=1;i<=n;++i)
		for(j=1;j<=n;++j){
			tmp[i][j]=INT_MAX;
			for(k=1;k<=n;++k)
				if(ans[i][k]!=-1&&g[k][j]!=-1)
					tmp[i][j]=min(tmp[i][j],ans[i][k]+g[k][j]);
		}
	for(i=1;i<=n;++i)
		for(j=1;j<=n;++j)
			ans[i][j]=tmp[i][j]==INT_MAX?-1:tmp[i][j];
	return ;
}
void mul2()
{
	int i,j,k;
	for(i=1;i<=n;++i)
		for(j=1;j<=n;++j){
			tmp[i][j]=INT_MAX;
			for(k=1;k<=n;++k)
				if(g[i][k]!=-1&&g[k][j]!=-1)
					tmp[i][j]=min(tmp[i][j],g[i][k]+g[k][j]);
		}
	for(i=1;i<=n;++i)
		for(j=1;j<=n;++j)
			g[i][j]=tmp[i][j]==INT_MAX?-1:tmp[i][j];	
	return ;
} 

int main()
{
	int i,L,m,s,e;
	memset(g,-1,sizeof(g));
	scanf("%d%d%d%d",&L,&m,&s,&e);
	n=0;
	while(m--){
		int w,a,b;
		scanf("%d%d%d",&w,&a,&b);		
		if(mymap[a]==0)	mymap[a]=++n;
		if(mymap[b]==0) mymap[b]=++n;
		g[mymap[a]][mymap[b]]=g[mymap[b]][mymap[a]]=w;
	}
	memset(ans,-1,sizeof(ans));
	for(i=1;i<=n;++i)
		ans[i][i]=0;
	while(L){
		if(L%2==1)
			mul1();//ans=ans*g;
	 	mul2();//g=g*g;	
		L=L/2;
	}
	printf("%d",ans[mymap[s]][mymap[e]]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: