At383 E - Sum of Max Matching
E.Sum of Max Matching
题意简述
给一张图,定义对于一条路径,将其权重定义为路径中一条边的最大权重, \(f(x,y)\)为从顶点 \(x\) 到顶点 \(y\) 的路径的最小路径权重,给定两个等长的一个A,B序列。要求重排B序列。求重排后的最小值\(\displaystyle \sum_{i=1}^{K} f(A_i, B_i)\)
解题思路
最小化最大权重路径和,很明显有单调性,先考虑二分,把小于某个权重值的不连通,大于某个权重值的联通。然后判断整张图的联通性。进一步观察,发现这个二分的过程和 \(Kruskal\) 最小生成树的过程很像。那么可以在重构树上贪心的考虑,当两个点不连通时,这两个点的最短路径就是当前遍历的路径长度,当两个点联通时,说明此前一定有一条更短路径使得两点互相可达。逐步遍历累加当前价值即可。使用并查集维护A和B序列的联通性,每次合并贪心的把A和B中可配对的点配对。
AC code
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const int N=2e5+5;
int f[N];
int cntA[N],cntB[N];
struct edge{
int x,y;ll w;
}a[N];
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
ll Union(int x,int y){
int fx=find(x),fy=find(y);
if(fx==fy) return 0;
f[fy]=fx;
cntA[fx]+=cntA[fy];
cntB[fx]+=cntB[fy];
ll Sam=min(cntA[fx],cntB[fx]);
cntA[fx]-=Sam,cntB[fx]-=Sam;
return Sam;
}
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int n,m,k;cin>>n>>m>>k;
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++) cin>>a[i].x>>a[i].y>>a[i].w;
sort(a+1,a+1+m,[](edge a,edge b){
return a.w<b.w;
});
for(int i=1,x;i<=k;i++) cin>>x,++cntA[x];
for(int i=1,x;i<=k;i++) cin>>x,++cntB[x];
ll ans=0;
for(int i=1;i<=m;i++) ans+=a[i].w*Union(a[i].x,a[i].y);
cout<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号