-
Problem:
https://pintia.cn/problem-sets/994805342720868352/problems/994805379664297984 -
tags:
dij最短路 map映射 大杂烩 -
Mean:
给出n个城市,m条边,起始城市X,终点城市ROM,求起点到终点的最小花费,花费相同要最大快乐,快乐相同要最少步数(平均值最大).同时求最小花费有几种走法 -
Solution
输入是城市,所以map(idx) 把城市名和编号映射一下.同时再反向映射(redx) 这样用编号获取城市名结尾输出方便一点
一遍dij,同时维护 dis(花费),roads(路数,几种走法),hip(步数,几跳),sum(快乐值),pth(路径). -
Mistakes
Max快乐值直接用sum[ed]就行了,最开始用Max_hp一直if记录最大值,然后测试点2会过不去. 应该是走其他花费更大的路会有更大的MAX,但不符合最小花费,然后因为是max( , ),所以大了以后调不会来,导致错误.样例里开头两个都是3 3,然后把roads 和 dis位置搞反了,交上去只对了样例,人傻了
-
Grains
复习了一下dij.
看了一下其他题解,好像没有比我更简洁的了.(虽然我写的很丑)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e2+3;
int n,k,a,b;
string s,x,y;
map<string,int> idx;
map<int,string> redx;
vector<int> ans;
int hp[N],e[N][N],dis[N],vis[N],pth[N],sum[N],roads[N],hip[N];
void ini(){
for(int i=1;i<=n;i++) dis[i]=1e9,vis[i]=0;
dis[1] = 0;
roads[1] = 1;
hip[1]=1;
}
void dij(int st){
vis[st] = 1;
int Min = 1e9,pos=-1;
for(int i=1;i<=n;i++){
if(e[st][i] && !vis[i]){
if(dis[st]+e[st][i]==dis[i]){
if( ((sum[st]+hp[i]==sum[i]) && (hip[st]+1<hip[i])) || sum[st]+hp[i]>sum[i]){
hip[i] = hip[st]+1;
sum[i] = sum[st]+hp[i];
pth[i] = st;
}
roads[i] += roads[st];
}
if(dis[st]+e[st][i] < dis[i]){
dis[i] = dis[st]+e[st][i];//更新花费
sum[i] = sum[st]+hp[i];//更新快乐值
roads[i] = roads[st];//更新总共几条路
hip[i] = hip[st]+1;//更新几跳(一共几个城市)
pth[i] = st;//更新路径
}
}
if(dis[i]<Min && !vis[i]) Min = dis[i],pos=i;
}
if(pos==-1) return ;
dij(pos);
}
int main(){
cin>>n>>k>>s;
idx[s] = 1;
for(int i=2;i<=n;i++){
cin>>x>>a;
idx[x] = i;
redx[i] = x;
hp[i] = a;
}
for(int i=1;i<=k;i++){
cin>>x>>y>>a;
e[idx[x]][idx[y]] = a;
e[idx[y]][idx[x]] = a;
}
ini();
dij(1);
int ed = idx["ROM"];
cout<<roads[ed]<<" "<<dis[ed]<<" "<<sum[ed]<<" "<<sum[ed]/(hip[ed]-1)<<endl;
while(pth[ed]>0) ans.push_back(ed),ed=pth[ed];
cout<<s;
for(int i=ans.size()-1;i>=0;i--){
cout<<"->"<<redx[ans[i]];
}
cout<<endl;
}