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(); // 回溯
}