PAT 1030 Travel Plan [dijkstra+DFS] [最短路径输出]

A traveler's map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (≤500) is the number of cities (and hence the cities are numbered from 0 to N−1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:

City1 City2 Distance Cost

where the numbers are all integers no more than 500, and are separated by a space.

Output Specification:

For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.

Sample Input:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

Sample Output:

0 2 3 3 40

------------------------------------我是题目和解题的分割线------------------------------------

又是一道Dijkstra最短路径问题。和这道题差不多PAT 1003 Emergency。有两种办法,一个是常规的Dijksra,另一个是Dijkstra+DFS,即先用Dijkstra记录最短路径,再通过DFS在这些最短路径中挑选出最佳路径。

//Dijkstra+DFS

#include<cstdio>
#include<vector>
#include<algorithm>
const int maxN = 540;
const int INF = 0x3fffffff;

using namespace std;

int N,M,S,D;
int nowCost = 0,minCost = INF;
int G[maxN][maxN],visited[maxN] = {},dis[maxN],cost[maxN][maxN];
//pre记录起点到终点的最短路径们,tmpPath存储DFS中的临时路径,minPath存储最佳路径 
vector<int> pre[maxN],tmpPath,minPath;

//最短路径 
void dijkstra(int index)
{
	fill(dis,dis+maxN,INF);
	dis[index] = 0;
	int i,j;
	for(i=0;i<N;i++)
	{
		//寻找未访问的结点中离起点最近的 
		int minI = index,minV = INF;
		for(j=0;j<N;j++)
		{
			if(!visited[j]&&dis[j]<minV)
			{
				minI = j;
				minV = dis[j];
			}
		}
		visited[minI] = 1; //标记为已访问 
		//更新最短路径 
		for(j=0;j<N;j++)
		{
			//如果未访问过&&边存在 
			if(!visited[j]&&G[minI][j]!=INF)
			{
				if(dis[minI]+G[minI][j]<dis[j])
				{
					dis[j] = dis[minI]+G[minI][j]; //更新 
					pre[j].clear(); //碰到更小的,需要先将之前的路径清空 
					pre[j].push_back(minI); //再加入结点j的新前驱minI 
				}
				else if(dis[minI]+G[minI][j]==dis[j])
					pre[j].push_back(minI); //如果有多条最短路径,加入 
			}
		}
	}
}

//最短路径中的最佳路径 
void dfs(int index)
{
	int i;
	//如果遍历至起点,即递归边界 
	//因为pre存储的是前驱结点,所以需要从终点遍历到起点 
	if(index==S) 
	{
		tmpPath.push_back(index); //加入临时结点 
		nowCost = 0; //当前路径的话费之和 
		for(i=tmpPath.size()-1;i>0;i--)
			nowCost += cost[tmpPath[i]][tmpPath[i-1]]; 
		if(nowCost<minCost) //更新最小花费和最佳路径 
		{
			minCost = nowCost;
			minPath = tmpPath;
		}
		tmpPath.pop_back();
		return;	
	}
	tmpPath.push_back(index); //加入该点 
	for(i=0;i<pre[index].size();i++) //并遍历该点的前驱结点 
		dfs(pre[index][i]);
	tmpPath.pop_back(); //删除该点,恢复原状 
}

int main()
{
	int i;
	//初始化图G和每条边的花费cost 
	fill(G[0],G[0]+maxN*maxN,INF); 
	fill(cost[0],cost[0]+maxN*maxN,INF);
	scanf("%d%d%d%d",&N,&M,&S,&D);
	for(i=0;i<M;i++)
	{
		int x,y,dis,cos;
		scanf("%d%d%d%d",&x,&y,&dis,&cos);
		G[x][y] = G[y][x] = dis;
		cost[x][y] = cost[y][x] = cos; //无向图 
	}
	dijkstra(S);
	dfs(D);
	for(i=minPath.size()-1;i>=0;i--)
		printf("%d ",minPath[i]); //输出最佳路径 
	printf("%d %d\n",dis[D],minCost); //输出最短距离和最小花费 
	return 0;
}
//Dijkstra 

#include<cstdio>
#include<algorithm>
const int maxN = 540;
const int INF = 0x3fffffff;

using namespace std;

int N,M,S,D;
int G[maxN][maxN],cost[maxN][maxN];
//pre记录前驱结点,costMin记录最低消费 
int visited[maxN] = {},dis[maxN],costMin[maxN],pre[maxN];

void dijkstra(int index)
{
	fill(dis,dis+maxN,INF);
	fill(costMin,costMin+maxN,INF); //初始化 
	dis[index] = 0;
	costMin[index] = 0;
	int i,j;
	for(i=0;i<N;i++)
	{
		int minI = index,minV = INF;
		for(j=0;j<N;j++)
		{
			if(!visited[j]&&dis[j]<minV)
			{
				minI = j;
				minV = dis[j];
			}
		}
		visited[minI] = 1;
		for(j=0;j<N;j++)
		{
			if(!visited[j]&&G[minI][j]!=INF)
			{
				if(dis[minI]+G[minI][j]<dis[j])
				{
					dis[j] = dis[minI] + G[minI][j]; //更新最短距离 
					costMin[j] = costMin[minI] + cost[minI][j]; //更新最低消费 
					pre[j] = minI; //更新前驱结点 
				}
				else if(dis[minI]+G[minI][j]==dis[j])
				{
					if(costMin[minI]+cost[minI][j]<costMin[j]) //如果相同距离下花费更少 
					{
						costMin[j] = costMin[minI]+cost[minI][j]; //更新最低消费 
						pre[j] = minI; //更新前驱结点 
					}
				}
			}
		}
	}
}

//递归逆序打印最短路径 
void printPath(int index)
{
	if(index==S) //遍历至起点,即递归边界 
	{
		printf("%d ",index);
		return;
	}
	printPath(pre[index]);
	printf("%d ",index);
}

int main()
{
	int i;
	fill(G[0],G[0]+maxN*maxN,INF);
	fill(cost[0],cost[0]+maxN*maxN,INF);
	scanf("%d%d%d%d",&N,&M,&S,&D);
	for(i=0;i<M;i++)
	{
		int x,y,dis,cos;
		scanf("%d%d%d%d",&x,&y,&dis,&cos);
		G[x][y] = G[y][x] = dis;
		cost[x][y] = cost[y][x] = cos;
	}
	dijkstra(S);
	printPath(D);
	printf("%d %d\n",dis[D],costMin[D]);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值