我們通過觀察發現:
a->b->c。
爲了讓路徑最短
只會有2種情況
a->b->c
a->x->b->x->c
即b到c時會與a有重複。
顯然,有重複邊時一定是更優的,因爲這樣就能讓邊權小的多算一遍,從而少算一遍邊權大的。
直接枚舉所有點,用前綴和優化即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 2e5+7;
int head[M],cnt;
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
int n,m,a,b,c;
ll d[M],d2[M],d3[M],p[M],sm[M];
int vs[M];
priority_queue<pair<int,int> ,vector<pair<int,int> >,greater<pair<int,int> > >q;
void dij()
{
for(int i=0;i<=n;i++)d[i]=0x3f3f3f3f,vs[i]=0;
d[a]=0;
q.push({d[a],a});
while(!q.empty())
{
pair<int,int> tp=q.top();q.pop();
int u=tp.second ;
if(vs[u])continue;
vs[u]=1;
for(int i=head[u];i;i=ee[i].nxt)
{
int v=ee[i].to,w=ee[i].val;
if(d[v]>d[u]+w)//1經過u再到v的距離小於 1直接到v的距離 則更新距離
d[v]=d[u]+w,q.push({d[v],v});
}
}
for(int i=0;i<=n;i++)d2[i]=0x3f3f3f3f,vs[i]=0;
d2[c]=0;
q.push({d2[c],c});
while(!q.empty())
{
pair<int,int> tp=q.top();q.pop();
int u=tp.second ;
if(vs[u])continue;
vs[u]=1;
for(int i=head[u];i;i=ee[i].nxt)
{
int v=ee[i].to,w=ee[i].val;
if(d2[v]>d2[u]+w)//1經過u再到v的距離小於 1直接到v的距離 則更新距離
d2[v]=d2[u]+w,q.push({d2[v],v});
}
}
for(int i=0;i<=n;i++)d3[i]=0x3f3f3f3f,vs[i]=0;
d3[b]=0;
q.push({d3[b],b});
while(!q.empty())
{
pair<int,int> tp=q.top();q.pop();
int u=tp.second ;
if(vs[u])continue;
vs[u]=1;
for(int i=head[u];i;i=ee[i].nxt)
{
int v=ee[i].to,w=ee[i].val;
if(d3[v]>d3[u]+w)//1經過u再到v的距離小於 1直接到v的距離 則更新距離
d3[v]=d3[u]+w,q.push({d3[v],v});
}
}
}
int nm=0;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
cin>>n>>m>>a>>b>>c;
int x,y,z;
cnt=0;
for(int i=0;i<=n;i++)head[i]=0;
for(int i=1;i<=m;i++)cin>>p[i];
for(int i=1;i<=m;i++)cin>>x>>y,add(x,y,1),add(y,x,1);
dij();
sort(p+1,p+1+m);
ll pr=2e18;
for(int i=1;i<=m;i++)sm[i]=sm[i-1]+p[i];
for(int i=1;i<=n;i++)
{
if(d[i]+d2[i]+d3[i]>m)continue;
pr=min(pr,sm[d[i]+d2[i]+d3[i]]+sm[d3[i]]);
}
cout<<pr<<endl;
}
return 0;
}