关于最短路径中的path

关于最短路径算法输出沿途路径的结点

第一次碰到这个问题是在这题:PAT甲级1030
一道最基础的最短路算法,但是一开始始终是内存和时间超限,原因是path数组没有赋值好,导致最后Vector无穷加原因,所以内存和时间超限。。错误代码如下:(原因也在代码中注释说明)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std ;
const int Inf = 99999999 ;
int G[510][510],pay[510][510],path[510],cost[510],dist[510],visit[510];
int main(){
	fill(G[0],G[0]+510*510,Inf) ;
	fill(pay[0],pay[0]+510*510,Inf) ;
	int N,M,start,destination ;
	cin >> N >> M >> start >> destination ;
	int v,w,d,c  ;
	while(M--){
		scanf("%d %d %d %d",&v,&w,&d,&c) ;
		G[v][w] = d ;
		G[w][v] = d ;
	 pay[v][w]= c ;
		pay[w][v] = c ;
	}
	for(int i = 0;i<N;i++){
		dist[i] = G[start][i] ; //注意这里给源结点的邻接顶点的距离都赋值好了,这是问题的开始
		cost[i] = pay[start][i];
		visit[i] =  0 ;	
		  
	}
	dist[start] = 0 ;
	cost[start] = 0 ;
	path[start] = -1 ;  //这里给源结点path设成-1没问题
	for(int node = 0;node<N;node++){
		int mincity = -1,mindist = Inf ;
		for(int i=0;i<N;i++)
			if(dist[i] < mindist && !visit[i]){
				mincity = i ;
				mindist = dist[i] ;
			}
		if(mincity == -1)
		  break ;
	    visit[mincity] = 1 ;
        for(int i = 0;i<N;i++){
        	if(G[mincity][i] != Inf && visit[i] == 0){
        	   /*问题就在这第一步,一开始mincity是源结点即start,于是开始更新start的邻接顶点的dist
        	   、cost和path,但是注意前面在为dist初始化时已经给start的邻接顶点的dist更新好了,
        	   也就是说下面这个if判断if(dist[i] > G[mincity][i] + dist[mincity])对于
        	   start来说始终不会执行,但是很蠢的一点是我前面并没有给start的邻接顶点的path更新好
        	   这样一来start的邻接顶点的path始终是随机值(前面也没有给path赋初值,以为path会自动更新)
               */
        		if(dist[i] > G[mincity][i] + dist[mincity]){
        			dist[i] = G[mincity][i] + dist[mincity] ;
        			cost[i] = pay[mincity][i] +cost[mincity];
        			path[i] = mincity ;
				}
				else if(dist[i] == G[mincity][i] + dist[mincity]){
					if(cost[i] > pay[mincity][i] + cost[mincity]){
						cost[i] = pay[mincity][i] + cost[mincity];
						path[i] = mincity ;
					}
				}
			}
		}
	}
	vector<int> a ;
	int p = destination ;
	while(path[p] != -1){
		a.push_back(p) ;
		p = path[p] ;
	}
	a.push_back(p) ;
	for(int i = a.size()-1;i>=0;i--)
	   cout << a[i] << " " ;
	cout << dist[destination] << " "<<cost[destination]  ;
	return 0 ;
}

解决方案

有两种解决办法:
1、在错误代码的基础上,将path和dist一样,在前面赋初值时将start的邻接点的path更新好。
2、在错误代码的基础上,将dist和path一样,前面初始化时不将start的邻接点的dist更新(即dist数组除了dist[start] = -1外,其余dist[i] 均等于Inf(无穷大)。。)

方案一代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std ;
const int Inf = 99999999 ;
int G[510][510],pay[510][510],path[510],cost[510],dist[510],visit[510];
int main(){
	fill(G[0],G[0]+510*510,Inf) ;
	fill(pay[0],pay[0]+510*510,Inf) ;
	int N,M,start,destination ;
	cin >> N >> M >> start >> destination ;
	int v,w,d,c  ;
	while(M--){
		scanf("%d %d %d %d",&v,&w,&d,&c) ;
		G[v][w] = d ;
		G[w][v] = d ;
	 pay[v][w]= c ;
		pay[w][v] = c ;
	}
	for(int i = 0;i<N;i++){
		dist[i] = G[start][i] ;
		cost[i] = pay[start][i];
		visit[i] =  0 ;		
		if(G[start][i] != Inf)
		   path[i] = start ; //解决的代码在这里,在这里将start的邻接点的path都已更新好
	}
	
	dist[start] = 0 ;
	cost[start] = 0 ;
	path[start] = -1 ;
	for(int node = 0;node<N;node++){
		int mincity = -1,mindist = Inf ;
		for(int i=0;i<N;i++)
			if(dist[i] < mindist && !visit[i]){
				mincity = i ;
				mindist = dist[i] ;
			}
		if(mincity == -1)
		  break ;
	    visit[mincity] = 1 ;
        for(int i = 0;i<N;i++){
        	if(G[mincity][i] != Inf && visit[i] == 0){
        		if(dist[i] > G[mincity][i] + dist[mincity]){
        			dist[i] = G[mincity][i] + dist[mincity] ;
        			cost[i] = pay[mincity][i] +cost[mincity];
        			path[i] = mincity ;
				}
				else if(dist[i] == G[mincity][i] + dist[mincity]){
					if(cost[i] > pay[mincity][i] + cost[mincity]){
						cost[i] = pay[mincity][i] + cost[mincity];
						path[i] = mincity ;
					}
				}
			}
		}
	}
	vector<int> a ;
	int p = destination ;
	while(path[p] != -1){
		a.push_back(p) ;
		p = path[p] ;
	}
	a.push_back(p) ;
	for(int i = a.size()-1;i>=0;i--)
	   cout << a[i] << " " ;
	cout << dist[destination] << " "<<cost[destination]  ;
	return 0 ;
}

方案二代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std ;
const int Inf = 99999999 ;
int G[510][510],pay[510][510],path[510],cost[510],dist[510],visit[510];
int main(){
	fill(G[0],G[0]+510*510,Inf) ;
	fill(pay[0],pay[0]+510*510,Inf) ;
	int N,M,start,destination ;
	cin >> N >> M >> start >> destination ;
	int v,w,d,c  ;
	while(M--){
		scanf("%d %d %d %d",&v,&w,&d,&c) ;
		G[v][w] = d ;
		G[w][v] = d ;
	 pay[v][w]= c ;
		pay[w][v] = c ;
	}
	for(int i = 0;i<N;i++){
        dist[i] = Inf ; //改动的地方在这里,将所以dist都赋值为Inf,这样下面那个if判断才能进去
		cost[i] = pay[start][i];
		visit[i] =  0 ;		
	}
	
	dist[start] = 0 ; //这里start的dist当然还是0了
	cost[start] = 0 ;
	path[start] = -1 ;
	for(int node = 0;node<N;node++){
		int mincity = -1,mindist = Inf ;
		for(int i=0;i<N;i++)
			if(dist[i] < mindist && !visit[i]){
				mincity = i ;
				mindist = dist[i] ;
			}
		if(mincity == -1)
		  break ;
	    visit[mincity] = 1 ;
        for(int i = 0;i<N;i++){
        	if(G[mincity][i] != Inf && visit[i] == 0){
        		if(dist[i] > G[mincity][i] + dist[mincity]){//这个if一开始会去更新start结点的dist和path、cost
        			dist[i] = G[mincity][i] + dist[mincity] ;
        			cost[i] = pay[mincity][i] +cost[mincity];
        			path[i] = mincity ;
				}
				else if(dist[i] == G[mincity][i] + dist[mincity]){
					if(cost[i] > pay[mincity][i] + cost[mincity]){
						cost[i] = pay[mincity][i] + cost[mincity];
						path[i] = mincity ;
					}
				}
			}
		}
	}
	vector<int> a ;
	int p = destination ;
	while(path[p] != -1){
		a.push_back(p) ;
		p = path[p] ;
	}
	a.push_back(p) ;
	for(int i = a.size()-1;i>=0;i--)
	   cout << a[i] << " " ;
	cout << dist[destination] << " "<<cost[destination]  ;
	return 0 ;
}

当然类似的问题又很多(BFS算法也会出现类似问题),重要的是搞清楚哪些地方自己已解决,哪些地方是要去更新或者说遍历,思路一定要清晰,这样才不会出错。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值