题目链接
题目分析
给出无向图,边和结点都有权重,查找最短路径;
当最短路径有多条时,选择结点权重总和最大的那条,若还有多条,选择平均结点权重最大的一条路径;
解题思路
使用Dijkstra()算法 查找最短路径;
本题满足最优子结构,故对于多条最短路径,可以在查找过程中就判断那条最佳(判断稍复杂),
也可以保存所有路径,最后筛选!
注意点:
结点是以三位大写字母组成的名字给出的,
可以使用map<string, int>
和 map<int, string>
形成映射关系;也可用Hash
字符串;
AC程序(C++)
/**********************************
*@ID: 3stone
*@ACM: PAT.A1087 All Roads Lead to Rome
*@Time: 18/8/22
*@IDE: VSCode 2018 + clang++
***********************************/
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<iostream>
using namespace std;
const int INF = 0x7fffffff;
const int maxn = 210;
int G[maxn][maxn]; //图
vector<int> pre[maxn]; // 前驱结点
int d[maxn]; //保存最小花费
bool vis[maxn]; //标记是否访问
int happiness[maxn]; //结点权重
int route_num[maxn]; //最短路径条数
int N, K;//结点数,边数
map<string, int> name_to_key;
map<int, string> key_to_name;
void Dijkstra(int s) {
d[s] = 0;
route_num[s] = 1;
for(int i = 1; i <= N; i++) {
int u = -1, MIN = INF;
for(int j = 1; j <= N; j++) {
if(vis[j] == false && d[j] < MIN){
u = j;
MIN = d[j];
}
}
if (u == -1) return;
vis[u] = true;
//更新
for(int v = 1; v <= N; v++) {
if(vis[v] == false && G[u][v] != INF) {
//更新最短路径
if(d[u] + G[u][v] < d[v]) {
d[v] = d[u] + G[u][v];
pre[v].clear();
pre[v].push_back(u);
route_num[v] = route_num[u];
} else if(d[u] + G[u][v] == d[v]) {
pre[v].push_back(u);
route_num[v] += route_num[u];
}
}//if
}//for - v
}//for - i
}//Dijkstra
vector<int> best_route;
int Max_Sum_Happ, Max_Avg_Happ;
//DFS筛选最佳最短路径
void dfs_route(int ed, vector<int> cur_route, int sum_happ, int sum_cty) {
if(ed == 1) { //回溯至起点
if(sum_happ > Max_Sum_Happ) {
Max_Sum_Happ = sum_happ;
Max_Avg_Happ = sum_happ / sum_cty;
best_route = cur_route;
} else if(sum_happ == Max_Sum_Happ && Max_Avg_Happ < (sum_happ / sum_cty) ) {
Max_Avg_Happ = sum_happ / sum_cty;
best_route = cur_route;
}
}
for(int i = 0; i < pre[ed].size(); i++) {
int v = pre[ed][i];
cur_route.push_back(v);
dfs_route(v, cur_route, sum_happ + happiness[v], sum_cty + 1);
cur_route.pop_back();
}
}
//初始化
void initialize() {
name_to_key.clear();
key_to_name.clear();
fill(d, d + maxn, INF);
fill(vis, vis + maxn, false);
fill(G[0], G[0] + maxn * maxn, INF);
fill(route_num, route_num + maxn, 0);
Max_Avg_Happ = -1;
Max_Sum_Happ = -1;
}
int main(){
char st[4]; //起点城市
char c1[4], c2[4]; //路径两端的城市名
int ed, cost; //重点编号,路径花费
while(scanf("%d %d %s", &N, &K, st) != EOF) {
//初始化
initialize();
int key = 1;
name_to_key[st] = key; //起点映射
key_to_name[key++] = st;
//输入N-1个城市的幸福度
for(int i = 1; i < N; i++) {
scanf("%s", c1);
if(strcmp(c1, "ROM") == 0) ed = key; //记录终点编号
name_to_key[c1] = key;
key_to_name[key] = c1;
cin >> happiness[key++];
}
//输入K条路径信息
for(int i = 0; i < K; i++) {
scanf("%s %s %d", c1, c2, &cost);
G[name_to_key[c1]][name_to_key[c2]] = cost;
G[name_to_key[c2]][name_to_key[c1]] = cost;
}
Dijkstra(1);
vector<int> cur_vector;
cur_vector.push_back(ed);
dfs_route(ed, cur_vector, happiness[ed], 0);
printf("%d %d %d %d\n", route_num[ed], d[ed], Max_Sum_Happ, Max_Avg_Happ);
for(int i = best_route.size() - 1; i > 0; i--) {
printf("%s->", key_to_name[best_route[i]].c_str());
}
printf("%s\n", key_to_name[best_route[0]].c_str());
}
return 0;
}