有一个消防队英雄,k个消防队成员,进行比赛,消防队英雄到达n个点的最短路的最大值和消防队成员到达n个点的最短路的最大值的C倍进行比较
方法1:
跑一次DIjkstra,从消防队英雄出发,然后跑K次最短路,求出值即可
方法2:
建立辅助点0点,0点到K个消防队成员有一个有向边,然后跑2次最短路,求出最大值即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define ll long long
using namespace std;
const int INF = 2147483647;
const int N = 1e3 + 5;
const int M = 1e6 + 5;
ll dis[N];//存路径
bool vis[N];
struct edge{
int next, to, w;
}e[M];
int head[N], tot;
inline void add(int u, int v, int w){//链式前向星存图
e[++tot].to = v;
e[tot].w = w;
e[tot].next = head[u];
head[u] = tot;
}
struct node{
ll dis;//dis表示到起始点的距离
int pos;//pos表示该点的下标
bool operator < (const node &x)const{//符号重载,对距离排序,针对于在优先队列里
return x.dis < dis;
}
};
void dijkstra(int s, int n){
for(int i = 0; i <= n; i++) dis[i] = INF, vis[i] = 0;
dis[s] = 0;
std::priority_queue<node> q;//构造优先队列
q.push((node){dis[s], s});//把初始位置和距离放进优先队列
while(!q.empty()){
node tmp = q.top();
q.pop();
int u = tmp.pos;
if(vis[u]) continue;//如果这个点走过了
vis[u] = 1;//标记走过
for(int i = head[u]; i; i = e[i].next){
int v = e[i].to;
if(!vis[v] && dis[v] > dis[u] + e[i].w){
dis[v] = dis[u] + e[i].w;
q.push((node){dis[v], v});
}
}
}
}
int super[N];
ll teamdis[N];
void solve(){
int V, E, S, K, C;
tot = 0;
memset(head, 0, sizeof(head));
memset(teamdis, 0x3f, sizeof(teamdis));
scanf("%d%d%d%d%d", &V, &E, &S, &K, &C);
for(int i = 1; i <= K; i++)
scanf("%d", &super[i]), add(0, super[i], 0);
for(int i = 1; i <= E; i++){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
dijkstra(S, V);
ll maxhero = 0;
for(int i = 1; i <= V; i++)
maxhero = max(maxhero, dis[i]);
ll maxfire = 0;
dijkstra(0, V);
for(int i = 1; i <= V; i++)
maxfire = max(maxfire, dis[i]);
printf("%lld
", maxhero <= maxfire * C ? maxhero : maxfire);
}
int main(){
int t;
scanf("%d", &t);
while(t--) solve();
}