CF1343 E. Weights Distributing

E. Weights Distributing

Question

给定由 n n 个点, m m 条边构成的无权无向图和 m m 个权值以及三个点 a , b , c a,b,c 。问如何分配这 m m 个权值才能使 l e n a b + l e n b c len_{a→b}+len_{b→c} 最小

Solution

有两种情况:

  1. a x b x c a→x→b→x→c l e n a x + l e n x b + l e n b x + l e n x c len_{a→x}+len_{x→b}+len_{b→x}+len_{x→c}
  2. a b c a→b→c l e n a c len_{a→c}

第二种情况是b在a→c的路上,算是1的特例,此时 l e n b x = 0 len_{b→x}=0
最优构造放权值的方法为, x b x→b 这条路上放的权值最小,因为这条路可能要计算两遍。
对每个点进行BFS,求其到其他点的距离,遍历每一个点为x的情况,记录最小值,为了计算路径方便,需要对 p p 数组排序,然后求其前缀和。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF  = 0x3f3f3f3f;
const ll  mod  = 1e9 + 7;
const ll  maxn = 1e6 + 5;
const int N = 2e5 + 5;

int n,m,A,B,C;
vector<int> G[N];
int dA[N],dB[N],dC[N];
ll p[N];

void bfs(int s,int *d){
	for(int i=1;i<=n;i++) d[i]=-1;
	queue<int>q;
	q.push(s);d[s]=0;
	while(!q.empty()){
		int t=q.front();q.pop();
		for(auto c:G[t]){
			if(d[c]==-1){
				d[c]=d[t]+1;
				q.push(c);
			}
		}
	}
}

void solve(){
	cin>>n>>m>>A>>B>>C;
	for(int i=1;i<=n;i++) G[i].clear();
	for(int i=1;i<=m;i++) cin>>p[i];
	sort(p+1,p+1+m);
	for(int i=1;i<=m;i++) p[i]+=p[i-1];
	for(int i=1;i<=m;i++){
		int u,v;cin>>u>>v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	bfs(A,dA);
	bfs(B,dB);
	bfs(C,dC);
	ll ans=1ll<<60;
	for(int i=1;i<=n;i++) 
		if(dA[i]+dB[i]+dC[i]<=m)
			ans=min(ans,p[dA[i]+dB[i]+dC[i]]+p[dB[i]]);
	cout<<ans<<'\n';
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Meulsama/article/details/105712351