队列优化dijstra---板子
留个板子
2019 南昌网络赛B
题意
v个点,e条边(可能重边,无影响),救火英雄在s点,剩下的k个救援队在k个位置,现在要求救火英雄对所有点的最短路的最大值乘1/c与k个救援队对所有点的最短路,取最小值输出(救火英雄要输出没乘1/c之前的)
分析
我们直接跑两边dijstra就行了,第一遍正常跑,以s为源点,第二遍,建立一个超级源点连接k个救援队的位置,权值为0,在跑一边dijstra,最后在比较
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int V = 1000 + 100;
const int E = V * V / 2;
struct node
{
int next, to, w;
}edge[E << 1];
struct zz
{
int id;
ll value;
zz(int _id = 0, ll _value = 0) : id(_id), value(_value) {}
bool operator < (const zz& a) const
{
return value > a.value;
}
};
bool vis[V];
int head[V], tot, v, e, s, k, c;
int kk[V];
ll dis[V];
void init()
{
tot = 0;
memset(head, -1, sizeof(head));
memset(vis, false, sizeof(vis));
}
void add(int u, int v, int w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot ++;
}
void dijstra(int x)
{
priority_queue <zz> q;
memset(dis, 0x7f, sizeof(dis));
dis[x] = 0;
q.push(zz(x, 0));
while(!q.empty())
{
zz tp = q.top();
q.pop();
int u = tp.id;
if(vis[u])
continue;
vis[u] = true;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int to = edge[i].to;
ll w = edge[i].w;
if(dis[to] > dis[u] + w)
{
dis[to] = dis[u] + w;
q.push(zz(to, dis[to]));
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while(t --)
{
init();
cin >> v >> e >> s >> k >> c;
for(int i = 0; i < k; i ++)
cin >> kk[i];
for(int i = 1; i <= e; i ++)
{
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
add(v, u, w);
}
dijstra(s);
ll nu1 = 0, nu2 = 0;
for(int i = 1; i <= v; i ++)
nu1 = max(nu1, dis[i]);
memset(vis, false, sizeof(vis));
for(int i = 0; i < k; i ++)
{
add(0, kk[i], 0);
add(kk[i], 0, 0);
}
dijstra(0);
for(int i = 1; i <= v; i ++)
nu2 = max(nu2, dis[i]);
if(nu1 <= nu2 * c)
cout << nu1 << endl;
else
cout << nu2 << endl;
}
}