E - Sum of Max Matching

题目链接:

题意:

给定一个无向图,一个序列a和一个序列b,b能够重排,求f(ai,bi)的最小值之和

其中f(ai,bi)代表ai节点到bi节点路径中权重最大的一条边的权值

思路:

最小化权值最大边 => kruskal求最小生成树
即每当两个连通块连通时,两个连通块内的节点到另一个连通块的节点的f(i,j)就确定了

利用带权并查集维护每个集合a序列的个数的数量和b序列的个数的数量,具体来说可以开一个cnt数组,如果是a中节点就++,否则--
每次连通都是正的一边和负的一边匹配

int n,m;
struct edge{
	int u,v,w;
	bool operator<(const edge&t)const{
		return w<t.w;
	}
};
vector<edge>e;
int f[maxn];
int find(int x){
	if(f[x]!=x)f[x]=find(f[x]);return f[x];
}

int cnt[maxn];
void solve(){
	int k;
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)f[i]=i;
	for(int i=1;i<=m;i++){
		int u,v,w;cin>>u>>v>>w;
		e.pb(edge{u,v,w});
	}
	vector<int>a(k+1);
	vector<int>b(k+1);
	for(int i=1;i<=k;i++){
		cin>>a[i];cnt[a[i]]++;
	}
	for(int i=1;i<=k;i++){
		cin>>b[i];cnt[b[i]]--;
	}
	int ans=0;
	sort(e.begin(),e.end());
	for(int i=0;i<e.size();i++){
		int x=e[i].u,y=e[i].v,w=e[i].w;
		x=find(x);y=find(y);
		if(x==y)continue;
		if(cnt[x]*cnt[y]<0)ans+=min(abs(cnt[x]),abs(cnt[y]))*w;
		cnt[x]+=cnt[y];
		f[y]=x;		
	}
	cout<<ans<<endl;
}
posted @ 2025-03-22 10:42  Marinaco  阅读(16)  评论(0)    收藏  举报
//雪花飘落效果