[题解]P5687 [CSP-S2019 江西] 网格图

P5687 [CSP-S2019 江西] 网格图

简单来说题目就是给定一个\(n\times m\)的网格图,同行边权相同,同列边权相同,求该网格图的最小生成树。

根据Kruskal算法的贪心思想,我们要优先选择权值尽可能小的行,并将这条边应用于尽可能多的列。列方向同理。

为了保证最终生成树的连通性,我们显然要先把最小的行和最小的列全都选上,如下图所示:

可以发现,如果当前已经选择了\(x\)组行方向上的边,此时如果选列方向上的边,则最多能放\(n-x\)条。列方向同理。

根据贪心思想,接下来我们选择第\(3\)行,此时我们最多能放\(8-1=7\)条边,将其全部选择。

根据贪心思想,接下来我们选择第\(6\)列(或第\(2\)列),此时我们最多能放\(5-2=3\)条边,将其全部选择。
我们发现最多只能放\(3\)条,否则一定会出现环。
……

有了上面的结论,我们就可以写出代码了。将行和列的权值分别排序,先各选去一个最小值,再用两个指针分别指向两个数组的第\(2\)为,每次选权值最小的行/列即可。

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define N 300010
using namespace std;
int n,m,a[N],b[N],posa,posb,ans,cnt;
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=m;i++) cin>>b[i];
	sort(a+1,a+1+n);
	sort(b+1,b+1+m);
	posa=1,posb=1;
	ans=a[1]*(m-1)+b[1]*(n-1),cnt=n+m-2;
	while(1){
		if(a[posa+1]<b[posb+1]){
			ans+=a[++posa]*(m-posb),cnt+=(m-posb);
		}else{
			ans+=b[++posb]*(n-posa),cnt+=(n-posa);
		}
		if(cnt==n*m-1) break;
	}
	cout<<ans<<"\n";
	return 0;
}
posted @ 2024-11-15 20:57  Sinktank  阅读(7)  评论(0编辑  收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2024 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.