题意
多组样例
给定(n,m,a,b,c),给定一个长度为(m)的数组(p[]),给定(m)条边,构成一个(n)个点(m)条边的无向图,(Mike)想要从(a)走到(b),再从(b)走到(c),你可以在他从(a)出发前将(p[])中的值分配到(m)条边上,问(Mike)最少走多少路程
分析
我们先将所有边的权值赋为(1),意为两点间的最小边数为多少
如果(a)到(b)和(b)到(c)的最短路不重合,那就直接将两条路上的边从小到大赋值即可,问题在于有重合的部分路径
发现(sum nleq 2cdot 10^5),我们可以枚举重合的点(i),让(Mike)走路径(a->i->b->i->c),然后求得边数,其中(i->b)的路径为(p[])中最小的几个元素,因为要走两遍,(i->a)和(i->c)的的路径为剩下元素中最小的元素
由于为无向图,(i)到三点距离即为三点到(i)距离,为表述方便,皆用(i)到三点表述
枚举(i)肯定不能以(i)为起点求最短路,否则时间复杂度太高,则可以以三点求最短路,然后枚举(i)
先计算(i->a)的边数,以(a)为起点,使用(Dijkstra)算法,再计算(i->b)的边数,以(b)为起点,使用(Dijkstra)算法,再计算(i->c)的边数,以(c)为起点,使用(Dijkstra)算法,其中不同的距离设为(disa[],disb[],disc[])
因为是求路径权值和,可直接排序后计算前缀和(sum[])
设(i->a)的路径为(disai),(i->)的b路径为(disbi),(i->c)的路径为(disci),则答案为(sum[disai + disbi + disci] + sum[disbi])的最小值(三边总的前缀和加上(i->b)的二次计算)
由于(i)到三点的路径不可能有重叠(否则取重叠点可使得答案更小),因此三条路径和小于(m),正好使得(disai + disbi + disci)不会超出(sum[])的范围
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
#define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
#define int ll
#define ls st<<1
#define rs st<<1|1
#define pii pair<int,int>
#define rep(z, x, y) for(int z=x;z<=y;++z)
#define com bool operator<(const node &b)
using namespace std;
const int maxn = (ll) 2e5 + 5;
const int mod = (ll) 1e9 + 7;
const int inf = 0x3f3f3f3f;
int T = 1;
struct edge {
int v, next, w;
} e[maxn << 1];
struct node {
int dis, u;
bool operator<(const node &b) const {
return dis > b.dis;
}
};
int cnt;
int head[maxn];
int disa[maxn];
int disb[maxn];
int disc[maxn];
bool vis[maxn];
void addedge(int u, int v, int w) {
e[++cnt].next = head[u];
e[cnt].v = v;
e[cnt].w = w;
head[u] = cnt;
e[++cnt].next = head[v];
e[cnt].v = u;
e[cnt].w = w;
head[v] = cnt;
}
int n, m, s;
void dijkstra_a() {
priority_queue<node> q;
disa[s] = 0;
node st;
st.dis = 0;
st.u = s;
q.push(st);
while (!q.empty()) {
node u = q.top();
q.pop();
if (vis[u.u])
continue;
vis[u.u] = true;
for (int i = head[u.u]; ~i; i = e[i].next) {
int v = e[i].v;
if (disa[v] > disa[u.u] + e[i].w) {
disa[v] = disa[u.u] + e[i].w;
node w;
w.dis = disa[v];
w.u = v;
q.push(w);
}
}
}
}
void dijkstra_b() {
priority_queue<node> q;
disb[s] = 0;
node st;
st.dis = 0;
st.u = s;
q.push(st);
while (!q.empty()) {
node u = q.top();
q.pop();
if (vis[u.u])
continue;
vis[u.u] = true;
for (int i = head[u.u]; ~i; i = e[i].next) {
int v = e[i].v;
if (disb[v] > disb[u.u] + e[i].w) {
disb[v] = disb[u.u] + e[i].w;
node w;
w.dis = disb[v];
w.u = v;
q.push(w);
}
}
}
}
void dijkstra_c() {
priority_queue<node> q;
disc[s] = 0;
node st;
st.dis = 0;
st.u = s;
q.push(st);
while (!q.empty()) {
node u = q.top();
q.pop();
if (vis[u.u])
continue;
vis[u.u] = true;
for (int i = head[u.u]; ~i; i = e[i].next) {
int v = e[i].v;
if (disc[v] > disc[u.u] + e[i].w) {
disc[v] = disc[u.u] + e[i].w;
node w;
w.dis = disc[v];
w.u = v;
q.push(w);
}
}
}
}
int num[maxn], sum[maxn];
void solve() {
memset(head, -1, sizeof(head));
cnt = 0;
int a, b, c;
cin >> n >> m >> a >> b >> c;
rep(i, 1, m)cin >> num[i];
sort(num + 1, num + 1 + m);
rep(i, 1, m)sum[i] = sum[i - 1] + num[i];
rep(i, 1, m) {
int u, v;
cin >> u >> v;
addedge(u, v, 1);
}
s = a;
rep(i, 1, n) {
disa[i] = disb[i] = disc[i] = inf;
vis[i] = false;
}
dijkstra_a();
s = b;
rep(i, 1, n)vis[i] = false;
dijkstra_b();
s = c;
rep(i, 1, n)vis[i] = false;
dijkstra_c();
int ans = LLONG_MAX;
rep(i, 1, n) {
int disai = disa[i];
int disbi = disb[i];
int disci = disc[i];
if (disai + disbi + disci > m)
continue;
int now = sum[disai + disbi + disci] + sum[disbi];
ans = min(ans, now);
}
cout << ans << '
';
}
signed main() {
start;
cin >> T;
while (T--)
solve();
return 0;
}