1087 All Roads Lead to Rome(dijikstra, 结点,最短路径数目,最短路径(边权)点权(快乐值))

本文深入解析了Dijkstra算法在寻找图中两点间最短路径的应用,特别是在考虑成本和快乐值两个维度下的最优路径选择。通过具体代码实现,展示了如何处理包含多个城市和路线的复杂场景,同时介绍了算法的具体步骤和关键数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1087 All Roads Lead to Rome (30 分)

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算法求出满足题意的路径,

            输出:1.满足题意最短路径数目(第一种方法直接通过dijkstra算法计算答案,第二种方法通过二维向量数组保存所有路径通过dfs筛选出满足题意的路径)

                       2.输出最短路径的权值(边权dis[end])

                       3.快乐值(点权w[end])

                       4.平均值 (通过快乐值 /路径结点总数)    w[end]/ ( 结点 node[end])

具体代码实现:

#include<iostream>
#include<map>
#include<vector>
using namespace std;
const int inf = 0x3f3f3f;
const int maxsize = 220;
int n,k;
string from,to,fname,cname,rname[maxsize];//输入的城市名字,存放城市名字的数组,rename[i]表示第i个城市的名字 rename冲突 
map<string,int> m;//将城市的字母依次转换为数字存放入map中 
int h,cost;//h表示城市的快乐值   
//w[i]表示点权(第i个城市的快乐值) happy[i] 表示从start到第i个点最短路径中的快乐值  
//num[k]表示从start到第i个点最短路径条数  
//node[i]表示从start到第i个点最短路径中的结点个数(当快乐值相等时 计算结点的个数)  
int  edge[maxsize][maxsize],dis[maxsize],w[maxsize],happy[maxsize],node[maxsize],num[maxsize];
int dispre[maxsize];
int revert=0;//将城市的字母名字转换为对应的数字 
vector<int>dispath; //存放最终要输出的路径 
bool visit[maxsize];
void disdfs(int end){ //将需要输出的路径存放入dispath中 
//	cout<<dispre[end]<<endl;
	if(dispre[end]==end){
		dispath.push_back(end);
		return;
	}
	disdfs(dispre[end]);
	dispath.push_back(end);
}
void dijkstra(int start){
	dis[start]=0;
	num[start]=1;//此时起始点最短路径为1 
	for(int i=0;i<n;i++){
		int min=inf,u=-1;
		for(int j=0;j<n;j++){
			if(dis[j]<min && visit[j]==false){
				min=dis[j];
				u=j;
			} 
		} 
		visit[u]=true;
		if(min==inf) return;
		for(int k=0;k<n;k++){
			if(visit[k]==false && edge[u][k]!=inf){
				if(dis[u]+edge[u][k] < dis[k]){//存在更短的路径
					dis[k]=dis[u]+edge[u][k];
					num[k]=num[u];//更新start到k的最短路径的条数 
					happy[k]=happy[u]+w[k];
					node[k]=node[u]+1;
					dispre[k]=u;
				}else if(dis[u]+edge[u][k]==dis[k]){
					num[k]=num[k]+num[u];//当存在相等的最短路径时,将k,u的最短路径总数相加 
					if(happy[u]+w[k] > happy[k]){
						happy[k]=happy[u]+w[k];
						node[k]=node[u]+1;
						dispre[k]=u;	
					}else if(happy[u]+w[k]==happy[k] && node[k] > node[u]+1){
						node[k]=node[u]+1;
						dispre[k]=u;
					}
				}
			}
		}
	}
}
int main(){
	ios::sync_with_stdio(false);
	fill(dis,dis+maxsize,inf);
	fill(edge[0],edge[0]+maxsize*maxsize,inf);
	cin>>n>>k>>fname;
	m[fname]=revert;//将名字转换对应的数字 
	rname[revert++]=fname;//将第一个名字放入名字数组中
	for(int i=0;i<n;i++){ //初始化存放路径的数组 
		dispre[i]=i;
	}
	for(int i=1;i<n;i++){ //i=1因为第一个名字已经被占用 
		cin>>cname>>h; //输入城市的名字和快乐值
		m[cname]=revert;//将名字转换对应的数字 
		rname[revert++]=cname;//将名字放入对应下标(自己的名字的对应的数字)名字数组中
		w[i]=h; //将点权(快乐值)加入点权数组中 
	}
	for(int i=0;i<k;i++){
		cin>>from>>to>>cost;
		edge[m[from]][m[to]] = edge[m[to]][m[from]] = cost;
	}
	int start=0,end=m["ROM"];
	dijkstra(start);
//	for(int i=0;i<sizeof(dis)/sizeof(int);i++){ //测试dis数组 
//		cout<<dis[i]<<endl;
//	} 
//	for(int i=0;i<n;i++){ //测试dis数组 
//		cout<<dis[i]<<endl;
//	} 
//	cout<<end<<endl;
//	cout<<dis[end]<<endl;
	disdfs(end);
	int avg = happy[end]/(node[end]);
	cout<<num[end]<<" "<<dis[end]<<" "<<happy[end]<<" "<<avg<<endl;
	for(int i=0;i<dispath.size();i++){
		if(i!=0)
			cout<<"->";
		cout<<rname[dispath[i]];//将城市数字名字对应的字母名字输出; 
	}
	
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值