【1087 30 Dijkstra】 All Roads Lead to Rome

传送门

题意

给定\(n\)个城市,\(m\)条⽆向边,从某个给定的起始城市出发,前往名为ROM的城市。每个城市 (除起始城市)都有一个点权,每条边有边权。求从起点到ROM所需要的最少花费,并输出其路径。如果路径有多条,给出幸福值最大的那条。如果仍然不唯一,选择路径上的城市平均幸福值最大的那条路径

数据范围

\(n\leq 200\)

题解

  • Dijkstra求最短路同时更新额外信息即可
  • pre记录最路径用于输出

Code

#include<bits/stdc++.h>
using namespace std;
const int N=210,INF=0x3f3f3f3f;
vector<int>pre,path;
bool st[N];
int h[N],g[N][N],d[N],sum[N],num[N],minpath[N];
int n,k,s,e,cnt,ans;
map<string,int>mp;
map<int,string>unmp;
int get(string s){
	if(mp[s]==0) { mp[s]=++cnt;unmp[cnt]=s;}
	return mp[s];
}
void dijkstra(){
	d[s]=0,num[s]=0,sum[s]=h[s],minpath[s]=1;
	for(int i=0;i<cnt;i++){
		int t=-1;
		for(int j=1;j<=cnt;j++)
			if(!st[j] && (t==-1||d[t]>d[j])) t=j;
		if(t==-1) return;
		st[t]=1;
		for(int j=1;j<=cnt;j++){
			if(d[j] > d[t]+g[t][j]){
				pre[j]=t;
				d[j]=d[t]+g[t][j];
				num[j]=num[t]+1;
				sum[j]=sum[t]+h[j];
				minpath[j]=minpath[t];
			}
			else if(d[j] == d[t]+g[t][j]) {
				minpath[j]+=minpath[t];
				if(sum[j]<sum[t]+h[j] || sum[j]==sum[t]+h[j] && num[j]>num[t]+1){
					pre[j]=t;
					num[j]=num[t]+1;
					sum[j]=sum[t]+h[j];
				}
			}
		}
	}
}
int main(){
	memset(g,0x3f,sizeof g);
	memset(d,0x3f,sizeof d);
	string t; cin>>n>>k>>t;
	s=get(t);
	for(int i=1;i<n;i++) {
		int hap; cin>>t>>hap; 
		int id=get(t);
		if(t=="ROM") e=id;
		h[id]=hap;
	}
	while(k--){
		string a,b; int dis; cin>>a>>b>>dis;
		int u=get(a),v=get(b);
		g[u][v]=g[v][u]=dis;
	}
	pre.resize(cnt+1);
	dijkstra();
	int now=e;
	while(now!=s){
		path.push_back(now);
		now=pre[now];
	}
	path.push_back(s);
	reverse(path.begin(),path.end());
	cout<<minpath[e]<<' '<<d[e]<<' '<<sum[e]<<' '<<(sum[e]/num[e])<<endl;
	for(int i=0;i<path.size();i++) cout<<(i==0?"":"->")<<unmp[path[i]];
}
posted @ 2021-03-07 14:08  Hyx'  阅读(117)  评论(0)    收藏  举报