1087 All Roads Lead to Rome (30 point(s))

1087 All Roads Lead to Rome (30 point(s))

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

Dijkstra算法的灵活使用、DFS。理解题意、小心求解是关键。

条条大路通罗马。每个到罗马的城市有一定的快乐值,每条道路有一定的花销。要求找出出发城市到罗马的最短路径。如果最短路径不唯一,找出其中可以得到快乐值最高的,如果仍然不唯一,找出其中经过城市最少的(即平均快乐值最高)。输出花销最短的路径的条数(快乐值、平均快乐值可以不同)、最短路径的花销、获得的最大快乐值以及平均快乐值,还有输出满足最后条件的路径。

关于数组维护。采用Dijkstra算法,因此首先要维护visit[]和dis[],分别记录i是否已经加入集合、出发点到i的最短路径。按照题意,还需要记录每个城市的快乐值h[],到达当前城市的快乐值sumH[]、到达每个城市的最短路径的条数paths[]、到达当前城市所经过的城市数量pastCities[]。特别地,为了能够最终给出这条路径,还需要记录前驱城市lastCity[]。

当每个结点newP加入集合,遍历每一个相邻的边(另一结点t和花销c),如果结点原本不可达或者经过newP有更小的距离,说明得到了更短的距离,则更新上述所有数组;如果经过newP有相同的距离,说明相同距离的路径也不唯一,维护paths[],再根据新路径的快乐值情况和所经过城市的数量,进一步确定是否需要维护其它数组(详见代码)。

理解算法的贪心策略,只要dest进入集合即可结束。

注意点:

1. 需要建立好城市名、城市数字编号的映射关系,使用map或者unordered_map根据value查询key,建立数组实现可以根据key查询value。区分map和unordered_map。

2. 回溯法得出路径

3. 数组的设置和更新

一定要小心,仔细!粗心大意的错误太多了!

关于Dijsktra算法:https://blog.csdn.net/coderwait/article/details/89161811

大神代码:https://blog.csdn.net/richenyunqi/article/details/80146150

#include<iostream>
#include<vector>
#include<cstring>
#include<map>
using namespace std;
const int MAX = 205;
struct Edge{
	int next;
	int cost;
	Edge(int n,int c){
		next = n;
		cost=c;
	}
};
vector<Edge> graph[MAX];//图 
int h[MAX],dis[MAX],sumH[MAX];//幸福值、从起点到该城市的距离、到达这个城市的幸福值 
int paths[MAX],lastCity[MAX], pastCities[MAX];//到达该城市的路径数、到达该城市的前驱城市、 
bool visit[MAX]={false};
map<string,int> mp;
string names[MAX];
void dfs(int city){//回溯法找出路径 
	if(city==0){
		cout<<names[city];return;
	}
	dfs(lastCity[city]);
	cout<<"->"<<names[city];
} 
int main(void){
	int N,K;cin>>N>>K;
	cin>>names[0];
	mp.insert({names[0],0});
	for(int i=1;i<N;i++){
		cin>>names[i]>>h[i];
		mp.insert({names[i],i});
	}
	string a,b;int c;
	for(int i=0;i<K;i++){
		cin>>a>>b>>c;
		int ax = mp[a],bx = mp[b];
		graph[ax].push_back(Edge(bx,c));
		graph[bx].push_back(Edge(ax,c));
	}
	int dest = mp["ROM"];
	memset(dis,-1,sizeof(dis));
	memset(sumH,0,sizeof(sumH));
	memset(paths,0,sizeof(paths));
	memset(pastCities,0,sizeof(pastCities)); 
	dis[0]=0;paths[0]=1;//初始化
	visit[0]=true;
	int newP = 0;
	while(!visit[dest]){
		for(int i=0;i<graph[newP].size();i++){
			int t = graph[newP][i].next;
			int c = graph[newP][i].cost;
			if(visit[t]) continue;
			if(dis[t]==-1||dis[newP]+c<dis[t]){//不可达,或者有更短的路径 
				dis[t] = dis[newP]+c;//更新到达距离
				sumH[t] = sumH[newP]+h[t];//更新到达该城市的幸福值
				paths[t] = paths[newP];//更新到达该城市的路径数 
				lastCity[t] = newP;//更新到达该城市的前驱城市 
				pastCities[t] = pastCities[newP]+1;//更新经过的城市数量 
			}
			else if(dis[newP]+c == dis[t]){//有相同长度的路径
				paths[t] += paths[newP];//更新到达该城市的路径数
				if(sumH[t]<sumH[newP]+h[t]||
				(sumH[t]==sumH[newP]+h[t]&&pastCities[t]>pastCities[newP]+1))
				{
					sumH[t] = sumH[newP]+h[t];//更新到达该城市的幸福值
					lastCity[t] = newP;//更新到达该城市的前驱城市  
					pastCities[t] = pastCities[newP]+1;//更新经过的城市数量 
				}  
			}
		}
		int min = 123123123;
		for(int i=0;i<N;i++){//寻找新的结点加入集合 
			if(visit[i]) continue;
			if(dis[i]==-1) continue;
			if(dis[i]<min){
				min = dis[i];
				newP = i;
			}
		}
		visit[newP] = true;
	} 
	cout<<paths[dest]<<" "<<dis[dest]<<" "<<sumH[dest]<<" "<<sumH[dest]/pastCities[dest]<<endl;
	dfs(dest);
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值