PAT (Advanced Level) Practice 1087 All Roads Lead to Rome (30分)(Dijkstra+超详细步骤注释)

1.题目

Indeed there are many different tourist routes from our city to Rome. You are supposed to find your clients the route with the least cost while gaining the most happiness.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers N (2≤N≤200), the number of cities, and K, the total number of routes between pairs of cities; followed by the name of the starting city. The next N−1 lines each gives the name of a city and an integer that represents the happiness one can gain from that city, except the starting city. Then K lines follow, each describes a route between two cities in the format City1 City2 Cost. Here the name of a city is a string of 3 capital English letters, and the destination is always ROM which represents Rome.

Output Specification:

For each test case, we are supposed to find the route with the least cost. If such a route is not unique, the one with the maximum happiness will be recommanded. If such a route is still not unique, then we output the one with the maximum average happiness -- it is guaranteed by the judge that such a solution exists and is unique.

Hence in the first line of output, you must print 4 numbers: the number of different routes with the least cost, the cost, the happiness, and the average happiness (take the integer part only) of the recommanded route. Then in the next line, you are supposed to print the route in the format City1->City2->...->ROM.

Sample Input:

6 7 HZH
ROM 100
PKN 40
GDN 55
PRS 95
BLN 80
ROM GDN 1
BLN ROM 1
HZH PKN 1
PRS ROM 2
BLN HZH 2
PKN GDN 1
HZH PRS 1

Sample Output:

3 3 195 97
HZH->PRS->ROM

2.题目分析

类似题目:数据结构与算法题目集(中文)7-35 城市间紧急救援 (25分)

1.思路:使用Dijkstra算法,记录最短路径的距离cost,记录总的happiness,记录节点个数,记录路径。

2.详细讲解见代码注释

3.代码

#include<iostream>
#include<stack>
#include<string>
#include<cstring>
#include<unordered_map>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX 300
#define INF 0x3f3f3f3f
int edges[MAX][MAX];//存放图
int n, m;
int pathcount[MAX];//到达当前节点的最短路径的数量
int visited[MAX];//节点是否访问
int dist[MAX];//距离数组,各个点离当前点的距离
int happiness[MAX];//各个点的幸福指数
int amount[MAX];//当前路径走到现在经过的节点数
int sum[MAX];//当前路径走到现在这个节点累加的幸福指数
int path[MAX];//记录路径
int DJ(int v)
{
	fill(dist, dist + MAX, INF);//将初始的距离函数设为INF还是edges[][]都可以
	/*for (int i = 0; i < n; i++)
	{
		dist[i] = edges[v][i];
		sum[i] = happiness[i];
		amount[i] = 1;
	}*/
	dist[v] = 0;
	pathcount[v] = 1;
	/*开始没有设置visited[v]为1,而是将dist[v]设为0,并且初始化pathcount[v] = 1;
	因为本题不只是求最短路径,还要求累加的幸福指数以及平均幸福指数,
	所以要记录int pathcount[MAX];这样在下面else if (edges[u][j] + min == dist[j])
	会进入if执行pathcount[j] += pathcount[u];从而实现pathcount的赋值
	
	如果开始只是设置visited[v]为1,u就是离v最近的节点,在加入u查看是否能
	缩短v到其它节点的距离时,pathcount[j] += pathcount[u];失效,因为
	pathcount[u]数值未被赋值
	*/
	for (int i = 0; i < n; i++)//因为v节点也要走一遍,所以遍历n次,否则是n-1次
	{
		int min=INF, u = -1;
		for (int j = 0; j < n; j++)
		{
			if (visited[j] == 0 && min > dist[j]) { min = dist[j]; u = j; }
		}
		if (u == -1)return -1;
		visited[u] = 1;
		for (int j = 0; j < n; j++)
		{
			if (visited[j] == 0 && edges[u][j] != INF)
			{
				if ( edges[u][j] + min < dist[j])
				{
					dist[j] = edges[u][j] + min;//更新缩短后的距离
					amount[j] = amount[u] + 1;//向前走了一步,节点数加一
					sum[j] = sum[u] + happiness[j];//幸福总数加上当前节点的幸福指数
					pathcount[j] = pathcount[u];//因为只是缩短距离,未出现距离相等情况,所以到达当前节点的最短路径的数量不动
					path[j] = u;//保存路径
				}
				else if (edges[u][j] + min == dist[j])//出现距离相等,注意这里的else if!如果写成if,可能上面刚执行完距离更新,这里就pathcount[j] += pathcount[u];导致结果偏大
				{
					pathcount[j] += pathcount[u];//更新最短路径的数量
					if (sum[j] < sum[u]+happiness[j])//如果算上当前节点后happiness变多
					{
						amount[j] = amount[u] + 1;
						sum[j] = sum[u] + happiness[j];
						path[j] = u;
					}
					else if (sum[j] == sum[u]+happiness[j])//如果happiness加起来也一样
					{
						/*double uaverage = 1.0*(sum[u] + happiness[j]) / (amount[u] + 1);
						double vaverage = 1.0*(sum[j]) / (amount[j]);
						if (uaverage > vaverage)
						{
							amount[j] = amount[u] + 1;
							path[j] = u;
						}*/
						if (amount[j] > amount[u] + 1)
						{
							amount[j] = amount[u] + 1;
							path[j] = u;
						}
					}
				}
			}
		}
	}
}
int main()
{
	string start, end = "ROM";
	scanf("%d %d", &n, &m);
	unordered_map<string, int>name;//缩短寻找时间
	unordered_map<int, string>number;
	cin >> start;
	string a, b;
	int c;
	name[start] = 0;
	number[0] = start;
	for (int i = 1; i < n; i++)
	{
		cin >> a >> happiness[i];
		name[a] = i;
		number[i] = a;
	}
	fill(edges[0], edges[0] + MAX*MAX, INF);
    
	for (int i = 0; i < m; i++)
	{
		cin >> a >> b >> c;
		edges[name[a]][name[b]] = edges[name[b]][name[a]] = c;
	}
	DJ(name[start]);
	vector<int>road;
	stack<int>p;
	int d = name["ROM"];
	p.push(d);
	while (path[d] != 0)
	{
		p.push(path[d]);
		d = path[d];
	}
	road.push_back(name[start]);
	while (!p.empty())
	{
		road.push_back(p.top()); p.pop();
	}

	printf("%d %d %d %d\n", pathcount[name["ROM"]], dist[name["ROM"]], sum[name["ROM"]], sum[name["ROM"]]/amount[name["ROM"]]);
	for (int i = 0; i < road.size(); i++)
	{
		printf("%s%s", i == 0 ? "" : "->", number[road[i]].c_str());
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值