The 2019 Asia Nanchang Online Programming Contest B. Fire-Fighting Hero

题目

题目不难,就是太难懂。
给一个无向图,有一个点 s,和 k 个点,问点 s 到其他点的最短路径的最大值,跟 k 个点到其他点最短路径的最大值。谁的小谁赢,不过比之前 s 得出的值要乘以 c 再比。输出赢家的值。

分析

直接分别跑 nlogn 的 dijk 就行,就是算 k 个点的时候先将他们连起来,加 k -1条权值为 0 的边。
(邻接表存图,点比较少)

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define fuck(x) cout << (x) << endl
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e3 + 10;
const int M = 1e3 + 10;

int t, v, e, s, k, c;
int dd[M][M];
int kk[N];

struct node{
int u, di;
node(int u, int di):u(u), di(di){}
friend bool operator < (const node& a, const node& b) {
return a.di > b.di;
}
};

int dis[N];

int dijk(int rt){
memset(dis, INF, sizeof(dis)), dis[rt] = 0; // 初始化
priority_queue<node> q; // 优先小的 di
q.push((node(rt, 0))); // 放入 1 号点
while(!q.empty()){
node cnt = q.top();
q.pop();
if(dis[cnt.u] != cnt.di)
continue;
for(int i = 1; i <= v; i++){
if(dis[i] > cnt.di + dd[cnt.u][i]){
dis[i] = cnt.di + dd[cnt.u][i];
q.push(node(i, dis[i]));
}
}
}
int res = 0;
for(int i = 1; i <= v; i++){
res = max(res, dis[i]);
}
return res;
}


int main(){
scanf("%d", &t);
while(t--){
memset(dd, INF, sizeof(dd));
scanf("%d%d%d%d%d", &v, &e, &s, &k, &c);
for(int i = 0; i < k; i++){
scanf("%d", &kk[i]);
}
for(int i = 0, x, y, z; i < e; i++){
scanf("%d%d%d", &x, &y, &z);
dd[x][y] = dd[y][x] = min(dd[x][y], z);
}
int slen = dijk(s);
for (int i = 1; i < k; i++){
dd[kk[i - 1]][kk[i]] = dd[kk[i]][kk[i - 1]] = 0;
}
int ans = dijk(kk[0]);
if(slen > ans * c){
printf("%d\n", ans);
}else{
printf("%d\n", slen);
}
}
return 0;
}