2018-12-04 pat5-4315丨dijkstra丨思维转化

【原题连接】https://www.nowcoder.com/pat/5/problem/4315

【维基介绍】https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm

题意

给n个城市(0~n-1),求从0城市到“ROM”城市的一些数据,并且要输出路径。数据要有:等花费最短路的条数,最短路的花费,最短路上的happy值,最短路上的平均happy值。输出优先,花费相对最少,happy值相对最大,平均happy值相对最大,的一条路径。

 

思路

一开始我用DFS莽了一下,居然过了八个测试点,有点惊讶。为了完美过题我还是开始尝试写了Dijkstra,心里还是有点抗拒的。一写真的暴露出很多问题。

把距离数组的思想用在花费和happy值上就可以了。我一开始的障碍是,最短路的条数如何解决,看了别人的做法才知道,也可以用一个数组a[i]表示到i点最短路的条数,那么对于相邻j点的a[j],如果i->j也是一条最短路,那么a[j]+=a[i];否则就覆盖过去。

在细节上,还有因为我生疏的缘故写错的,比如忘了走过的点要continue,同一个点只要在更新最短路的时候push一次就可以了等。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> par;
const int MAXN = 215;
const int INF = 0x3f3f3f3f;
int n,k;

string iton[MAXN],st,ed;
map<string,int> ntoi;
int happ[MAXN];             //happiness of city i;
int cost[MAXN][MAXN];       //cost from i to j;
vector<int>g[MAXN];         //adj-list
int trace[MAXN],top_trace;  //save the answer
int ds[MAXN];               //min distance cost of city i
int hp[MAXN];               //max happiness of city i while ds
int ct[MAXN];               //number of visited cities when in city i
int df[MAXN];               //number of different ways to get city i while ds
int pre[MAXN];              //last city visited before city i for the optimal way
bool vis[MAXN];             //whether city i is visited


void dijkstra(int u){
    priority_queue<par,vector<par>,greater<par> >Q;
    memset(ds,INF,sizeof ds);

    ds[0]=0;
    df[0]=1;
    //for(int i=0;i<n;i++)
        Q.push({0,0});
    while(!Q.empty()){
        u=Q.top().second;
        Q.pop();
        if(vis[u])continue;
        vis[u]=true;

        for(int v:g[u]){
            if(vis[v])continue;
            //printf("%d\n",cost[u][v]);
            int altv=ds[u]+cost[u][v];
            int alth=hp[u]+happ[v];
            int altc=ct[u]+1;

            if(altv<ds[v]){
                df[v]=df[u];
                ds[v]=altv;
                hp[v]=alth;
                ct[v]=altc;
                pre[v]=u;
                Q.push({altv,v});
            }else if(altv==ds[v]){
                df[v]+=df[u];
                if(alth>hp[v]){
                    hp[v]=alth;
                    ct[v]=altc;
                    pre[v]=u;
                }else if(alth==hp[v]){
                    if(altc<ct[v]){
                        hp[v]=alth;
                        ct[v]=altc;
                        pre[v]=u;
                    }
                }
            }
        }

    }
}

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>k>>st;//0~n-1;
    ed="ROM";

    iton[0]=st;
    ntoi[st]=0;
    for(int i=1;i<n;i++){
        cin>>iton[i]>>happ[i];
        //cout<<iton[i]<<happ[i]<<endl;
        ntoi[iton[i]]=i;
    }

    string s1,s2;
    for(int i=1,u,v,c;i<=k;i++){
        cin>>s1>>s2>>c;
        u=ntoi[s1];
        v=ntoi[s2];
        cost[u][v]=c;
        cost[v][u]=c;
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }

    dijkstra(0);
    int ied=ntoi[ed];
    while(ied){
        trace[++top_trace]=ied;
        ied=pre[ied];
    }

    ied=ntoi[ed];
    cout<<df[ied]<<' '<<ds[ied]<<' '<<hp[ied]<<' '<<hp[ied]/ct[ied]<<endl;
    cout<<st;
    for(int i=top_trace;i>0;i--){
        cout<<"->"<<iton[trace[i]];
    }
    cout<<endl;
    return 0;
}
/*
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
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值