浙大pat | 浙大pat 牛客网甲级 1002 All Roads Lead to Rome (30)迪杰斯特拉算法改进

链接:https://www.nowcoder.com/questionTerminal/bf8045decb1348a3bd6967305cbdad4c
来源:牛客网

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

输入描述:
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.

 

输出描述:
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 recommended.  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 recommended route.  Then in the next line, you are supposed to print the route in the format "City1->City2->...->ROM".

示例1

输入

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

输出

3 3 195 97
HZH->PRS->ROM

这一题都不难,就是:相当的复杂

这一题使用的是迪杰斯特拉算法,并且是改进的算法,一般的迪杰斯特拉只需要考虑路径最短就行了,但是这个算法需要考虑快乐最高,平均快乐最高,还需要考虑最短路径一共有多少条(这里的最短路径只需要考虑路径最短就好了),并且这里给的城市还不是ID,直接是字符串

所以首先可以使用一个哈希表,unordered_map。用来id和string之间的转换,然后需要7个数组,分别用来记录当前城市最佳路径上一级,当前城市最短路径方案个数,当前路径当前城市需要经过的城市的总数,当前城市最佳方案快乐累计值,当前城市最佳方案最短路径长度,使用一个theEdges来记录城市之间的路径长度,使用一个theCityHappy来记录每个城市的快乐值,vst数组用来记录该城市是否访问过

之后就可以直接使用迪杰斯特拉算法解决这个问题,以后要记得改进的迪杰斯特拉算法!

当以后做题的时候,题目给出的不是ID而是string的情况下,可以使用哈希表来在sting和ID之间进行转换,这样能够极大的节省运行时间和编程数量!

以后在做题的时候,当可以申请很大的数组,使用空间换时间的时候一定要记得去换,这种题对空间的要求不高,反而对时间的要求非常的严格,

也就是说在做题的时候不要怕申请很大的数组,很少会limit的

以后不要使用临接表了,使用邻接矩阵,因为复杂度低一些,也直观一些

还有就是有关memset的使用,需要头文件memory.h这个函数的意义是给数组指定的字节数赋予你给定的value值,这里需要注意的是,赋值的时候是一个字节一个字节的赋值的,所以当对int数组进行赋值的时候会出错,但是当给int数组赋值-1的时候反而不会出错,因为-1二进制就全是1!

也就是说memset适合给bool类型数组赋值,给char型数组赋值,以及整形数组赋值-1(一维二维都行)!

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory.h>
#include <vector>
using namespace std;
#define MAX 200000000
int theCityHappy[203];

int pre[203];
int routCount[203];
int cityCount[203];
int happyCount[203];
int cityLengthCount[203];
int theEdges[203][203];
bool vst[203];
int main()
{
	int N, K;
	string tmp,startCity,tmp2;
	int h;
	int one, two;
	int theRomId;
	unordered_map<string, int> cityToId;
	unordered_map<int, string> idToCity;
	memset(vst, false, sizeof(vst));
	memset(theEdges, -1, sizeof(theEdges));
	
	cin >> N >> K >> startCity;
	cityToId.insert(make_pair(startCity, 0));
	idToCity.insert(make_pair(0, startCity));
	for (int i = 1; i <= N - 1; i++)
	{
		cin >> tmp >> h;
		if (tmp == "ROM") theRomId = i;
		cityToId.insert(make_pair(tmp, i));
		idToCity.insert(make_pair(i, tmp));
		theCityHappy[i] = h;
	}
	for (int i = 0; i < K; i++)
	{
		cin >> tmp >> tmp2 >> h;
		one = cityToId[tmp]; two = cityToId[tmp2];
		theEdges[one][two] = h;
		theEdges[two][one] = h;
	}
	for (int i = 0; i < N; i++)
	{
		cityLengthCount[i] = MAX;
	}
	//迪杰斯特拉算法
	vst[0] = true;  pre[0] = -1; cityCount[0] = 1;
	for (int i = 1; i < N; i++)
	{
		if (theEdges[0][i] != -1 && !vst[i])
		{
			pre[i] = 0; routCount[i] = 1;
			cityCount[i] = 1; happyCount[i] = theCityHappy[i];
			cityLengthCount[i] = theEdges[0][i];
		}
	}
	int _min;
	while (1)
	{
		_min = MAX-1;
		for (int i = 1; i < N; i++)
		{
			if (!vst[i] && cityLengthCount[i] < _min)
			{
				h = i;
				_min = cityLengthCount[i];
			}
		}
		if (h == theRomId) break;
		vst[h] = true;
		for (int i = 1; i < N; i++)
		{
			if (!vst[i]&& theEdges[h][i]!=-1)
			{
				if (cityLengthCount[h] + theEdges[h][i] < cityLengthCount[i])
				{
					pre[i] = h;
					routCount[i] = routCount[h];
					cityCount[i] = cityCount[h]+1;
					happyCount[i] = happyCount[h] + theCityHappy[i];
					cityLengthCount[i] = cityLengthCount[h] + theEdges[h][i];
				}
				else if (cityLengthCount[h] + theEdges[h][i] == cityLengthCount[i])
				{
					routCount[i] += routCount[h];
					if (happyCount[h] + theCityHappy[i] > happyCount[i])
					{
						pre[i] = h;
						cityCount[i] = cityCount[h] + 1;
						happyCount[i] = happyCount[h] + theCityHappy[i];
					}
					else if (happyCount[h] + theCityHappy[i] == happyCount[i])
					{
						if ((happyCount[h] + theCityHappy[i])*1.0 / (cityCount[h] + 1) > happyCount[i] * 1.0 / cityCount[i])
						{
							pre[i] = h;
							cityCount[i] = cityCount[h] + 1;
						}
					}
				}
			}
		}
	} 
	one = theRomId; vector<string> result;
	while (one != -1)
	{
		result.push_back(idToCity[one]);
		one = pre[one];
	}
	cout << routCount[theRomId] << " " << cityLengthCount[theRomId] << " " << happyCount[theRomId] << " " << (int)(happyCount[theRomId] * 1.0 / cityCount[theRomId]) << endl;
	for (int i = (int)result.size() - 1; i >= 0; i--)
	{
		cout << result[i];
		if (i != 0) cout << "->";
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值