Description
给定无向图和一个权值多重集,用它给无向图分配边权,要求是全排列,求路径 (a o b o c) 最短长度。
Solution
考虑到 (a o b) 和 (b o c) 可能有一段重复的 (b - d),枚举 (d),这样只需求出 (a o d, d o b, b o d, d o c) 的最小值
设对某个 (d),(a-d,b-d,c-d) 长度分别为 (x,y,z),则我们会将最小的 (y) 个边权分配给 (b-d),剩余中最小的 (x+z) 个分配给 (a-d,c-d),因此可以在 (O(1)) 中计算出长度,故时间复杂度为 (O(n))
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
const int dbg = 0;
vector <int> g[N];
int p[N],dis[3][N],vis[N],t1,t2,n,m,a,b,c;
void bfs(int v0,int id)
{
queue <int> que;
que.push(v0);
dis[id][v0]=0;
while(!que.empty())
{
int p=que.front();
que.pop();
for(int q:g[p])
{
if(dis[id][q]>dis[id][p]+1)
{
dis[id][q]=dis[id][p]+1;
que.push(q);
}
}
}
}
void solve()
{
cin>>n>>m>>a>>b>>c;
for(int i=1;i<=m;i++)
{
cin>>p[i];
}
for(int i=1;i<=m;i++)
{
cin>>t1>>t2;
g[t1].push_back(t2);
g[t2].push_back(t1);
}
for(int i=1;i<=n;i++)
{
dis[0][i]=dis[1][i]=dis[2][i]=1e9;
}
dis[0][a]=dis[1][b]=dis[2][c]=0;
for(int i=1;i<=n;i++)
{
vis[i]=0;
}
bfs(a,0);
for(int i=1;i<=n;i++)
{
vis[i]=0;
}
bfs(b,1);
for(int i=1;i<=n;i++)
{
vis[i]=0;
}
bfs(c,2);
sort(p+1,p+m+1);
int ans=1e18;
int *da=dis[0],*db=dis[1],*dc=dis[2];
for(int i=1;i<=m;i++)
{
p[i]+=p[i-1];
}
if(dbg)
{
cout<<"sum seq: ";
for(int i=1;i<=m;i++)
{
cout<<p[i]<<" ";
}
cout<<endl;
}
int *sum=p;
for(int i=1;i<=n;i++)
{
int x=da[i],y=db[i],z=dc[i];
if(dbg)
{
cout<<" i="<<i<<" x,y,z="<<x<<y<<z<<endl;
}
if(x+y+z>m) continue;
int tmp=0;
tmp+=sum[x+y+z]+sum[y];
if(dbg)
{
cout<<" "<<sum[x+y+z]<<"+"<<sum[y]<<"="<<tmp<<endl;
}
ans=min(ans,tmp);
}
cout<<ans<<endl;
for(int i=1;i<=n;i++)
{
g[i].clear();
p[i]=0;
}
}
signed main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
}