PAT(甲级)渡劫(二)-All Roads Lead to Rome(30)

PAT(甲级)渡劫(二)-All Roads Lead to Rome(30)

题目大意:

在一个图中,寻找从杭州到罗马最短的路径,如果最短路径有多条,则需要求快乐值最多的,如果快乐值也一样多,则根据平均快乐值的多少进行取舍。

输出最短路径的条数,花费,快乐值以及平均快乐值和路径

算法思想:

可以使用Dijstra算法先求出最短的代价,然后用深度优先搜索计算最短路径的条数以及最大的快乐值和平均快乐值。

代码如下:
#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <string>

using namespace std;

struct node{
    int v;      // 结点编号
    int cost;
    node(int _v,int _cost):v(_v),cost(_cost){}  // 构造函数
};

int N;  // 城市的数量
int K;  // 道路的数量
int INF = 1e9;
string start;   // 起点城市名字
int happy[201]; // 存放各个城市的快乐值
map<string,int> stringToInt;    // 城市名字->编号
map<int,string> intToString;    // 编号->城市名字
vector<node> graph[201];        // 邻接链表
int cost[201];                  // 记录从起始城市到达点i的最少花费值
bool mark[201];                 // 标记数组
vector<int> pre[201];           // 记录前一个结点
vector<int> path;               // 记录路径
vector<int> tempPath;

int optHappy = 0;
double optAverageHappy = 0.0;
int cnt = 0;                  // 记录最短路径条数

void dijkstra(int s);
void dfs(int nowVisit);

int main(){
    //freopen("in.txt","r",stdin);
    cin>>N>>K>>start;
    stringToInt[start] = 0;     // 起始编号为0
    intToString[0] = start;

    string city;
    int happyness;              // 输入每个城市的快乐值
    for(int i = 1 ; i <= N-1 ; i++){
        cin>>city>>happyness;
        stringToInt[city] = i;
        intToString[i] = city;
        happy[i] = happyness;
    }

    string city1,city2;
    int co;                     // 花费            
    for(int i = 0 ; i < K ; i++){   // 输入边
        cin >> city1 >> city2 >> co;
        int id1 = stringToInt[city1];
        int id2 = stringToInt[city2];
        graph[id1].push_back(node(id2,co));
        graph[id2].push_back(node(id1,co));
    }

    int destination = stringToInt["ROM"];
    dijkstra(0);
    dfs(destination);
    cout<<cnt<<" "<<cost[destination]<<" "<<optHappy<<" "<<(int)optAverageHappy<<endl;
    for(int i = path.size()-1 ; i >= 0 ; i--){
        cout<<intToString[path[i]];
        if(i!=0){
            cout<<"->";
        }
    }

    return 0;
}

void dijkstra(int s){
    // 初始化到每个城市的花费为无穷大
    for(int i = 0 ; i < N ; i++){
        cost[i] = INF;
    }
    cost[s] = 0;   // 起点花费为0
    
    for(int i = 0 ; i < N ; i++){
        int u = -1,min = INF;   // 
        for(int j = 0 ; j < N ; j++){// 选择可达的且花费最少的结点
            if(!mark[j] && cost[j] < min){
                min = cost[j];
                u = j;
            }
        }
        if(u == -1){    // 若不可达
            return;
        }
        mark[u] = true;  // 将花费最少的可达结点加入集合K
        for(int j = 0 ; j < graph[u].size() ; j++){ // 更新新加入结点的邻接结点的值
            int v = graph[u][j].v;
            int co = graph[u][j].cost;
            if(!mark[v]){   // 若该邻接结点没有被访问
                if(cost[u] + co < cost[v]){
                    cost[v] = cost[u] + co;
                    pre[v].clear();
                    pre[v].push_back(u);
                }else if(cost[u] + co == cost[v]){
                    pre[v].push_back(u);
                }
            }
        }
    }
}

void dfs(int nowVisit){
    tempPath.push_back(nowVisit);   // 将当前点加入临时路径
    if(nowVisit == 0){      // 递归边界(到了Dijkstra的起点)
        cnt++;              // 最短路径条数加1
        int happyValue = 0;
        for(int i = tempPath.size() - 2 ; i >= 0 ; i--){// 倒着访问(排除无快乐值的起点)
            happyValue += happy[tempPath[i]];
        }
        double averageHappyValue = 1.0 * happyValue/(tempPath.size()-1);
        if(happyValue > optHappy){
            optHappy = happyValue;
            optAverageHappy = averageHappyValue;
            path = tempPath;
        }else if(happyValue == optHappy && averageHappyValue > optAverageHappy){
            optAverageHappy = averageHappyValue;
            path = tempPath;
        }
        tempPath.pop_back();
        return;
    }
    for(int i = 0 ; i < pre[nowVisit].size(); i++){
        dfs(pre[nowVisit][i]);  // 继续DFS当前结点v的各个前驱
    }           
    tempPath.pop_back();    // 回溯
}
运行结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值