A1087 All Roads Lead to Rome (30point(s))
题意
找出花费最小并且获得最大幸福度的路径,如果不唯一则选择最短的。
思路
考察dijskra算法,这里用了优先队列。
Sample Input:
6 7 HZH
ROM 100
PKN 40
GDN 55
PRS 95
BLN 80
ROM GDN 1
BLN ROM 1
HZH PKN 1
PRS ROM 2
BLN HZH 2
PKN GDN 1
HZH PRS 1
Sample Output:
3 3 195 97
HZH->PRS->ROM
#include "bits/stdc++.h"
using namespace std;
const int N = 210;
vector<int> links[N];
int vis[N];
int G[N][N];
int dis[N];
int w[N];
vector<int> pre[N];
struct cmp{
bool operator()(int id1,int id2){
return dis[id1] >= dis[id2];
}
};
void dsijk(int startId,int n){
fill(dis,dis+N,INT32_MAX);
dis[startId] = 0;
fill(vis,vis+N,0);
priority_queue<int,vector<int>,cmp> q;
q.push(startId);
for (int i = 0; i < n; ++i) {
int id;
while (true){
if (q.empty()) return;
else if (vis[q.top()]) {
q.pop();
continue;
}
id = q.top(), q.pop();
break;
}
vis[id] = 1;
for (int j = 0; j < n; ++j) { // for all node
if (vis[j] || G[id][j] == INT32_MAX) continue;
int ed = dis[id] + G[id][j];
if (ed < dis[j]){
dis[j] = ed, q.push(j);
pre[j].clear(), pre[j].push_back(id);
} else if (ed == dis[j]){
q.push(j), pre[j].push_back(id);
}
}
}
}
vector<int> temp,ans;
int ans_w = 0;
int cnt_lessPath = 0;
void dfs(int id,int eid){
if (id == eid){
cnt_lessPath ++;
temp.push_back(id);
int sum = 0;
for(int t:temp) sum += w[t];
if( ans.empty()
|| sum > ans_w
|| (sum == ans_w && temp.size() < ans.size())) {
ans = temp;
ans_w = sum;
}
temp.pop_back();
return;
}
temp.push_back(id);
for(int t:pre[id]) dfs(t,eid);
temp.pop_back();
}
int main(){
// freopen("input.txt","r",stdin);
int n, k; cin >> n >> k;
vector<string> names(n);
unordered_map<string,int> name2Id;
for (int i = 0; i < n; ++i) {
cin >> names[i];
name2Id[names[i]] = i;
if (i) scanf("%d",&w[i]);
}
fill(G[0],G[0]+N*N,INT32_MAX);
for (int i = 0; i < k; ++i) {
string s1,s2; int v;
cin >> s1 >> s2 >> v;
G[name2Id[s1]][name2Id[s2]] = G[name2Id[s2]][name2Id[s1]] = v;
}
int startId = 0; int endId = name2Id["ROM"];
dsijk(startId,n);
dfs(endId,startId);
cout << cnt_lessPath << " " << dis[endId] << " " << ans_w << " " << (int)ans_w/(ans.size()-1) << endl;
reverse(ans.begin(),ans.end());
for (int i = 0; i < ans.size(); ++i) {
cout << names[ans[i]];
if (i != ans.size()-1) printf("->");
else printf("\n");
}
}