输出最短路字典序路径 floyed & dijkstra

以hdu1385为例子。http://acm.hdu.edu.cn/showproblem.php?pid=1385

一:floyed+路径输出

我们除了用dis[][]存储个点之间的距离之外,我们还需要用一个path[][]二维数组记录路径。开始看了网上有很多path记录的方法。

  1. 用path[i][j]记录终点j的(其实实现不了)
  2. 用path[i][j]记录终点j的前一个结点(开始自己用的就是这种方法,但是不知道错哪里了)
  3. 用path[i][j]记录i结点的后面的第一个结点。

我们采用的是第三种方法

初始化:

memset(path,-1,sizeof(path));
for(int i=1;i<=N;i++){
	for(int j=1;j<=N;j++){
		scanf("%d",&dis[i][j]);
		if(-1==dis[i][j])
			dis[i][j]=inf;
		else 
			path[i][j]=j;
	}
}

更新 

//这个是普遍的写法,hdu1385还需要在此基础上加点东西。
for(res k=1;k<=N;k++){
	for(res i=1;i<=N;i++){
		for(res j=1;j<=N;j++){
			if(dis[i][j]>dis[i][k]+dis[k][j]+cost[k]){
				dis[i][j]=dis[i][k]+dis[k][j]+cost[k];
				path[i][j]=path[i][k];
			}
		}
	}
}
//思考:为甚麽不是path[i][j]=k呢?
//因为path[i][k]记录的是i到k路径中i后面的第一个结点。path[i][j]现在有更短的路可以到达
//就是通过i——K——j,那么当前path[i][j]就要更新为新路径中i后面的第一个结点

hdu1385ac代码

#include <bits/stdc++.h> 
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define res register int 
const int maxn=1005;
int dis[maxn][maxn];
int N,cost[maxn];
int path[maxn][maxn];

void floyed()
{
	for(res k=1;k<=N;k++){
		for(res i=1;i<=N;i++){
			for(res j=1;j<=N;j++){
				if(dis[i][j]>dis[i][k]+dis[k][j]+cost[k]){
					dis[i][j]=dis[i][k]+dis[k][j]+cost[k];
					path[i][j]=path[i][k];
				}else if(dis[i][j]==dis[i][k]+dis[k][j]+cost[k]&&path[i][j]>path[i][k]){
					path[i][j]=path[i][k];
				}
			}
		}
	}
}

void init()
{
	memset(path,-1,sizeof(path));
	for(int i=1;i<=N;i++){
		for(int j=1;j<=N;j++){
			scanf("%d",&dis[i][j]);
			if(-1==dis[i][j])
				dis[i][j]=inf;
			else
				path[i][j]=j;
		}
	}
	for(int i=1;i<=N;i++)
		scanf("%d",&cost[i]);
}

//void output(int i,int j)
//{
//	if(-1==path[i][j]) return;
//	output(i,path[i][j]);
//	printf("%d-->",path[i][j]);
//	if(i!=path[i][j]&&path[i][j]!=path[path[i][j]][j]) output(path[i][j],j);
//}

void output(int from,int to)
{
	int u=from,v=to;
	while(u!=v){
		printf("%d-->",u);
		u=path[u][v];
	}
	
}

int main()
{
	while(EOF!=scanf("%d",&N)&&N)
	{
		init();
		floyed();
		int from,to;
		while(EOF!=scanf("%d%d",&from,&to)&&-1!=from&&-1!=to){
			printf("From %d to %d :\n",from,to);
			printf("Path: ");
			output(from,to);
			printf("%d\n",to);
			printf("Total cost : %d\n\n",dis[from][to]);
		}
	}
	return 0;
}

二:dijkstra+路径输出

这个采用的是记录前驱的方法。因为有多条路径,所以对于某一个结点,它是有多个前驱的。定义vector<int> pre[maxn],用不定长数组可以记录多个前驱。

对于路径长度的比较,我们可以这样:

然后我们定义记录后驱的数组,vector<int> next[maxn],将pre转换成每一个结点next,比如1有pre为2,那2就有next为1。

然后我们从起始结点开始深搜就行了,每次都选取序号最小的继续深搜,这样最后得到的就是字典序。 

 想的很美好,可惜下面的代码没ac。。。不知道错哪了,哪位大佬有空可以看看。

  1. if( !vis[j] && len[j]>len[p]+dis[p][j]+cost[j]),没有访问过,并且需要更新结点
    之前存储的前驱就要clear掉,然后再push_back(p)
  2. if(!vis[j]&&len[j]==len[p]+dis[p][j]+cost[j]),没有访问过,并且len[j]==len[p]+dis[p][j]+cost[j]
    就push_back(p) (push_back(p)之后,就说明此时的j结点有多个前驱)
//wa的代码!!不知道错哪里了。
#include <bits/stdc++.h> 
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define res register int 
const int maxn=1005;
int dis[maxn][maxn];
int N,cost[maxn];
vector<int> pre[maxn];
vector<int> NEXT[maxn];

void change(int A,int B)//将pre转换成NEXT 
{
	if(A==B) return;
	else{
		for(res i=0;i<pre[B].size();i++){
			int n=pre[B][i];
			NEXT[n].push_back(B);
			change(A,n);
		}
	}
}

int dijkstra(int A,int B)
{
	for(int i=1;i<=N;i++){
		pre[i].clear(); 
		NEXT[i].clear();
	} 
	int vis[maxn],len[maxn];
	memset(vis,0,sizeof(vis));
	for(res i=1;i<=N;i++){
		len[i]=min(inf,dis[A][i]+cost[A]+cost[i]);
		if(inf!=dis[A][i]) pre[i].push_back(A);
	}
	pre[A].clear();
	len[A]=cost[A];
	vis[A]=1;
	for(res i=1;i<N;i++){
		int minc=inf,p=-1;
		for(res j=1;j<=N;j++){
			if(!vis[j]&&len[j]<minc){
				minc=len[j];
				p=j;
			}
		}		
		if(inf==minc) break;
		vis[p]=1;
		for(res j=1;j<=N;j++){
			if(!vis[j]&&len[j]>len[p]+dis[p][j]+cost[j]){
				len[j]=len[p]+dis[p][j]+cost[j];
				pre[j].clear();
				pre[j].push_back(p); 
			}else if(!vis[j]&&len[j]==len[p]+dis[p][j]+cost[j]){
				res k;
				for(k=0;k<pre[j].size();k++){
					if(p==pre[j][k]) break;
				}
				if(pre[j].size()==k)
					pre[j].push_back(p); 
			}
		}
	}
	change(A,B);
//	for(res i=1;i<=N;i++){
//		printf("%d :",i);
//		for(res j=0;j<pre[i].size();j++){
//			printf("%d ",pre[i][j]);
//		}
//		printf("\n");
//	}
//	for(res i=1;i<=N;i++){
//		printf("%d :",i);
//		for(res j=0;j<NEXT[i].size();j++){
//			printf("%d ",NEXT[i][j]);
//		}
//		printf("\n");
//	}
	return len[B];
}

void init()
{
	for(int i=1;i<=N;i++){
		for(int j=1;j<=N;j++){
			scanf("%d",&dis[i][j]);
			if(-1==dis[i][j]){
				dis[i][j]=inf;
			}
		}
	}
	for(int i=1;i<=N;i++)
		scanf("%d",&cost[i]);
}

void output(int from,int to)
{
	if(from==to){
		printf("%d\n",to);
		return;
	}else{
		int minc=inf;
		for(int i=0;i<NEXT[from].size();i++){
			if(minc>NEXT[from][i]){
				minc=NEXT[from][i];
			}
		}
		printf("%d-->",from);
		output(minc,to);
	}
}

int main()
{
	while(EOF!=scanf("%d",&N)&&N)
	{
		init();
		int from,to;
		while(EOF!=scanf("%d%d",&from,&to)&&-1!=from&&-1!=to){
			printf("From %d to %d :\n",from,to);
			int sum=dijkstra(from,to);
			printf("Path: ");
			output(from,to);
			printf("Total cost : %d\n\n",sum-cost[from]-cost[to]);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41755258/article/details/85138049