1087 All Roads Lead to Rome (30分)

这是一篇关于PAT甲级考试中的一道题目,问题涉及求解从特定起点到终点城市的最小花费路径。文章通过dijkstra算法解决最短路问题,并在寻找最小花费的同时考虑最大快乐值和最少步数。作者使用map进行城市名与编号的映射,并在一次dijkstra遍历中维护了花费、路径数、步数和快乐值。在解决问题的过程中,作者意识到最大快乐值应直接取sum[ed],避免了错误的发生。此外,文章还提及了在处理样例时的一个小失误,提醒读者注意细节。

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

  1. Problem:
    https://pintia.cn/problem-sets/994805342720868352/problems/994805379664297984

  2. tags:
    dij最短路 map映射 大杂烩

  3. Mean:
    给出n个城市,m条边,起始城市X,终点城市ROM,求起点到终点的最小花费,花费相同要最大快乐,快乐相同要最少步数(平均值最大).同时求最小花费有几种走法

  4. Solution
    输入是城市,所以map(idx) 把城市名和编号映射一下.同时再反向映射(redx) 这样用编号获取城市名结尾输出方便一点
    一遍dij,同时维护 dis(花费),roads(路数,几种走法),hip(步数,几跳),sum(快乐值),pth(路径).

  5. Mistakes
    Max快乐值直接用sum[ed]就行了,最开始用Max_hp一直if记录最大值,然后测试点2会过不去. 应该是走其他花费更大的路会有更大的MAX,但不符合最小花费,然后因为是max( , ),所以大了以后调不会来,导致错误.

    样例里开头两个都是3 3,然后把roads 和 dis位置搞反了,交上去只对了样例,人傻了

  6. 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值