PAT.A1087 All Roads Lead to Rome

返回目录在这里插入图片描述

题意

有N个城市,M条无向边。现在需要从某个给定的起始城市出发(除了起始城市外,其他每个城市都有一个“幸福值”),前往名为“ROM”的城市。给出每条边所需要消耗的花费,求从起始城市出发,到达城市ROM所需要的最少花费,并输出最少花费的路径。如果这样的路径有多条,则选择幸福值最大的那条。如果还有多条,则选择平均值最大的那条,平均值即幸福值之和/路径上的城市数量。

样例(可复制)

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
//output
3 3 195 97
HZH->PRS->ROM

注意点

  1. 本题可以使用Dijkstra或Dijkstra+DFS的方式解决,笔者使用了前者。
  2. 相比普通的Dijkstra,本题在算法流程中还需要加入计算:①路径数量②最大幸福值③当前的路径上的顶点数④保存最优路径上的每个点的前驱节点
  3. 对于城市名字使用map<string,int>和map<int,string>在输入时就进行一一对应,也可以考虑使用hash存储编号
#include<bits/stdc++.h>
using namespace std;

const int N=220;
int n,m,ed;//城市数量,边数 ,ROM城市编号 
int G[N][N];//图 
//W为幸福值,dis为距离,C为累计的幸福值,num为路径数,pt为路径的点数,pre为前驱节点 
int W[N],dis[N],C[N],num[N]={0},pt[N]={0},pre[N];
bool vis[N];//标记是否访问过 
map<string,int> nametoid;
map<int,string> idtoname;
void Dijkstra(){
	fill(dis,dis+N,INT_MAX);
	fill(C,C+N,INT_MAX);
	memset(vis,false,sizeof(vis));
	dis[0]=0;
	C[0]=0;//起点幸福值为0 
	num[0]=1;//路径初始为1 
	while(!vis[ed]){
		int minn=INT_MAX,v;
		for(int i=0;i<n;i++){//找最短路径 
			if(!vis[i]&&dis[i]<minn){
				minn=dis[i];
				v=i;
			}
		}
		vis[v]=true;
		for(int i=0;i<n;i++){
			if(!vis[i]&&G[v][i]>0&&dis[i]>dis[v]+G[v][i]){
				dis[i]=dis[v]+G[v][i];
				pre[i]=v;
				num[i]=num[v];
				C[i]=C[v]+W[i];
				pt[i]=pt[v]+1;
			}else if(G[v][i]>0&&dis[i]==dis[v]+G[v][i]){
				num[i]+=num[v];//想想为什么不是num[i]=num[v]+1 
				if(C[v]+W[i]>C[i]){//如果幸福值更大 
					pre[i]=v;
					C[i]=C[v]+W[i];
					pt[i]=pt[v]+1;
				}else if(C[v]+W[i]==C[i]){//幸福值相等 
					double preavg=1.0*C[i]/pt[i];//之前的平均值 
					double nowavg=1.0*C[i]/(pt[v]+1);//现在的平均值
					if(nowavg>preavg){
						pre[i]=v;
						pt[i]=pt[v]+1;
					}
				} 
			}
		}
	}
	
}
void printpath(int v){
	if(v==0){
		cout<<idtoname[0];
		return;
	}
	printpath(pre[v]);
	cout<<"->"<<idtoname[v];
}
int main(){
	string name;
	cin>>n>>m>>name; 
	nametoid[name]=0;
	idtoname[0]=name;
	for(int i=1;i<n;i++){
		cin>>name>>W[i];
		nametoid[name]=i;
		idtoname[i]=name;
	}
	while(m--){
		string a,b;
		int dd;
		cin>>a>>b>>dd;
		G[nametoid[a]][nametoid[b]]=G[nametoid[b]][nametoid[a]]=dd;
	}
	ed=nametoid["ROM"];
	Dijkstra();
	printf("%d %d %d %d\n",num[ed],dis[ed],C[ed],C[ed]/pt[ed]); 
	printpath(ed);//递归打印路径 
    return 0;
}
发布了177 篇原创文章 · 获赞 5 · 访问量 6649

猜你喜欢

转载自blog.csdn.net/a1920993165/article/details/105588892