1087 All Roads Lead to Rome (30)(30 分)

dijkstra模板题
问题的关键在于不同情况的判断
相等的时候会改变哪些值
最短的时候更新哪些值
代码量基本90-150行了很难优化
见注释

#include <bits/stdc++.h>
using namespace std;
#define MAXN 0X3F3F3F3F
int graph[500][500];
map<string, int> happy;//某个城市的快乐值
map<int, string> rev;//反向查找
map<string, int> id;
int path[500];//保存路径
int vis[500];//是否访问
int spend[500];//到该点的开销
int happiness[500];//到该点的快乐程度
int route[500];//经过的路线条数
int num[500];//经过的顶点个数
int N,K;
void dijkstra(){
    //初始化部分
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            graph[i][j]=MAXN;
        }
        spend[i]=MAXN;//初始花费无穷大
    }
    for(int i=1;i<=K;i++){//根据映射修改邻接表
        string a,b;
        int q;
        cin>>a>>b>>q;
        graph[id[a]][id[b]]=graph[id[b]][id[a]]=q;
    }
    spend[1]=0;//起点花费=0
    path[1]=-1;//起点之前没有其他点了
    route[1]=1;//路线为1条
    num[1]=1;//一个顶点
    for(int i=1;i<N;i++){//dijkstra核心部分
        int mmin=MAXN;//初始化最小值
        int v;
        for(int j=1;j<=N;j++){//找到花销最小的点
            if(!vis[j]){
                if(spend[j]<mmin){
                    mmin=spend[j];
                    v=j;
                }
            }
        }
        vis[v]=1;//访问
        for(int j=1;j<=N;j++){//访问他的邻接点
            if(!vis[j]&&graph[v][j]!=MAXN){//可到达并且没有访问
                if(spend[v]+graph[v][j]<spend[j]){//更新最值
                    spend[j]=spend[v]+graph[v][j];
                    happiness[j]=happiness[v]+happy[rev[j]];//最短路径,叠加快乐值
                    num[j]=num[v]+1;//顶点个数++
                    route[j]=route[v];//路线沿用他的
                    path[j]=v;//保存路径
                }
                else if(spend[j]==spend[v]+graph[v][j]){//花销一样
                    route[j]+=route[v];//路线加上新增的
                    if(happiness[j]<happiness[v]+happy[rev[j]]){//由于是花销一样的,看快乐程度 取大的快乐程度
                        happiness[j]=happiness[v]+happy[rev[j]];
                        num[j]=num[v]+1;//节点++
                        path[j]=v;//保存路径
                    }
                    else if(happiness[j]==happiness[v]+happy[rev[j]]){//快乐程度一样
                        if(num[j]>num[v]+1){//用节点数更少的
                            num[j]=num[v]+1;
                            path[j]=v;//保存路径
                        }
                    }
                }
            }   
        }
    }
}
void print(int t){
    if(t==1){
        printf("%s",rev[1].c_str());
        return;
    }
    print(path[t]);
    printf("->%s",rev[t].c_str() );
}
int main(){
    cin>>N>>K;
    string start;
    cin>>start;
    id[start]=1;//开始点为1
    rev[1]=start;
    for(int i=2;i<=N;i++){
        string temp;
        int cost;
        cin>>temp>>cost;
        happy[temp]=cost;//某点的快乐程度
        id[temp]=i;//对应关系表
        rev[i]=temp;//反向对应
    }
    dijkstra();
    printf("%d %d %d %d\n",route[id["ROM"]],spend[id["ROM"]],happiness[id["ROM"]], happiness[id["ROM"]]/(-1+num[id["ROM"]]));
    print(id["ROM"]);//递归倒序输出
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值