Weights Distributing
题目链接:https://codeforces.com/contest/1343/problem/E
题目描述:
给定n个点m条无向边,再给你a,b,c三个点和m个值,现在要求你将这m个值分配这m条边,使a->b->c的路径的权值最小
思路:
分类讨论,一种情况是a->b和b->c这两条路上无交点,这样直接将权值排序后取最小即可,第二种就是两条路上有交点,这时候我们一定可以找到一个交点x,该交点把路径分为a->x,x->b,b->x,x->c这四段路线,因为b->x和x->b本质上是同一条路,所以我们需要优先把较小的权值分配给这条路,可以先用bfs求出a、b、c三个点到所有点的单位距离,接着贪心赋值即可。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = 0x3f3f3f3f;
const ll N = 1e6;
const double PI = acos(-1.0);
#define Test ll tesnum;tesnum = read();while(tesnum--)
ll read();
ll val[N];
vector<int> g[N];
void bfs(int id,vector<int> &v)
{
v[id] = 0;
queue<int> q;
q.push(id);
while(!q.empty()){
int u = q.front();
q.pop();
for(int nx:g[u]){
if(v[nx]==INF){
v[nx] = v[u]+1;
q.push(nx);
}
}
}
}
int main()
{
Test{
int n,m,a,b,c;
cin>>n>>m>>a>>b>>c;
for(int i = 1; i <= m; i++){
cin>>val[i];
}
for(int i = 1; i <= n; i++)g[i].clear();
sort(val+1,val+1+m);
for(int i = 1; i <= m; i++){
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
val[i] += val[i-1];
}
vector<int> disa(n+1,INF);
vector<int> disb(n+1,INF);
vector<int> disc(n+1,INF);
bfs(a,disa);
bfs(b,disb);
bfs(c,disc);
ll ans = 2e16;
for(int i = 1; i <= n; i++){
if(disa[i]+disb[i]+disc[i]>m)continue;
ans = min(ans,val[disb[i]]+val[disa[i]+disb[i]+disc[i]]);
}
cout<<ans<<endl;
};
return "BT7274", NULL;
}
inline ll read() {
ll hcy = 0, dia = 1;char boluo = getchar();
while (!isdigit(boluo)) {if (boluo == '-')dia = -1;boluo = getchar();}
while (isdigit(boluo)) {hcy = hcy * 10 + boluo - '0';boluo = getchar();}
return hcy * dia;
}