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;
}