首先用map解决城市名字到编号的映射。
题目给了最优路径的三个判断标准:
第一标准:边权累积最小。
第二标准:点权累积最大。
第三标准:平均点权最大。
下面判断这三个标准能否用dijkstra算法处理,
标准1:
已知 S -> PATH1 -> B -> D是第一标准最优,证明 S -> PATH1 -> B 也是最优。
假设存在 S -> PATH2 -> B 比它更短,那么 S -> PATH2 -> B -> D 比已知的最短路径更短
出现矛盾,所以不存在,得证。
标准2:同理可证。
标准3:已知 S -> PATH1 -> B -> D是第三标准最优,证明 S -> PATH1 -> B 也是最优。
PATH1上点的个数为 N1,点权累积为 W1
PATH2上点的个数为 N2,点权累积为 W2
那么已知最优路径到 D 的平均点权为 (WS+W1+WB+WD)/(N1+3)
到B的平均点权 (WS+W1+WB)/(N1+2)
假设存在 S -> PATH2 -> B 比它更优,即
(WS+W2+WB)/(N2+2) > (WS+W1+WB)/(N1+2)
证明 :(WS+W2+WB+WD)/(N2+3) > (WS+W1+WB+WD)/(N1+3)
//未完待续
标准3暂时不可证,稳妥的策略是用dijkstra处理前两个标准,找到多条路径,最后DFS找出第三标准最优的路径。如果三个标准全部一起dijkstra,pat测试点也能通过,但数据可能不全面。
#include <iostream>
#include <climits>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
const int maxv = 200;
const int INF = INT_MAX;
int N, K, S, D, mark=-1;
int v_weight[maxv];
int graph[maxv][maxv]={};
int d[maxv]; //第一标准:边权累积最小
bool confirmed[maxv]={};
int path_count[maxv]={}; //路径条数
int v_w_sum[maxv]={}; //第二标准:点权累积最大
vector<int> pre[maxv];
map<string, int> mp;
int f_ave=0;
vector<int> path, t_path;
int change(string a); //城市名到编号互转
void init(int s);
void dijkstra(int s); //以s为起点
void DFS(int v, int n); //访问到v,已经累积点权sum,点数n
int main(){
string start;
cin>>N>>K>>start;
S = change(start); //起点
v_weight[S]=0;
for(int i=0; i<N-1; i++){
string city;
int w;
cin>>city>>w;
int c = change(city);
v_weight[c] = w;
if(city=="ROM") D = c; //终点
}
while(K--){
string city1, city2;
int cost;
cin>>city1>>city2>>cost;
int c1 = change(city1);
int c2 = change(city2);
graph[c1][c2] = graph[c2][c1] = cost;
}
dijkstra(S); //以第一、二标准找到最优路径
DFS(D, 0); //在pre形成的倒置图上深度优先遍历,找第三标准最优
cout<<path_count[D]<<' '<<d[D]<<' '<<v_w_sum[D]<<' '<<f_ave<<endl;
int nm = path.size();
for(int i=nm-1; i>=0; i--){
map<string, int>::iterator it;
for(it=mp.begin(); it!=mp.end(); it++){
if(it->second==path[i]) break;
}
cout<<it->first;
if(i>0) cout<<"->";
}
return 0;
}
int change(string a){
map<string, int>::iterator it = mp.find(a);
if(it!=mp.end()) return it->second;
else{
mark++;
mp.insert(make_pair(a, mark));
return mark;
}
}
void init(int s){
fill(d, d+N, INF);
d[s] = 0;
path_count[s] = 1;
v_w_sum[s] = v_weight[s];
return;
}
void dijkstra(int s){
init(s);
for(int k=0; k<N; k++){
int u=-1, min_d=INF;
for(int i=0; i<N; i++){
if(!confirmed[i] && d[i]<min_d){
u = i;
min_d = d[i];
}
}
if(u==-1) return;
confirmed[u] = true;
for(int j=0; j<N; j++){
//u->j
if(!confirmed[j] && graph[u][j]!=0){
if(d[u]+graph[u][j]<d[j]){
//第一标准更优,要换路径
d[j] = d[u] + graph[u][j];
v_w_sum[j] = v_w_sum[u] + v_weight[j];
path_count[j] = path_count[u];
pre[j].clear();
pre[j].push_back(u);
}
else if(d[u]+graph[u][j]==d[j]){
path_count[j] += path_count[u];
if(v_w_sum[u]+v_weight[j]>v_w_sum[j]){
//第一标准相同,第二标准更优,要换路径,即清空pre再添加
v_w_sum[j] = v_w_sum[u] + v_weight[j];
pre[j].clear();
pre[j].push_back(u);
}
else if(v_w_sum[u]+v_weight[j]==v_w_sum[j]){
//一、二标准都相同,直接添加
pre[j].push_back(u);
}
//如果第一标准相同,第二标准更差,则路径更差,不记录
}
//如果第一标准更差,则路径更差,不记录
}
}
}
return;
}
void DFS(int v, int n){
t_path.push_back(v);
if(v==S){
int a = v_w_sum[D]/n;
if(a>f_ave){
f_ave = a;
path = t_path;
}
t_path.pop_back();
return;
}
int t = pre[v].size();
for(int i=0; i<t; i++){
DFS(pre[v][i], n+1);
}
t_path.pop_back();
return;
}