D134 最小生成树 Kruskal 算法 P3073 [USACO13FEB] Tractor S
D134 最小生成树 Kruskal 算法 P3073 [USACO13FEB] Tractor S_哔哩哔哩_bilibili
P3073 [USACO13FEB] Tractor S - 洛谷
方格图,尽量走边权最小的格点,连通块的格点数达到一半(奇数时一半+1),输出连通块内的最大边权。
思路
对格点按坐标连续编号,对相邻的格点,用高度差的绝对值做边权连边
显然是求最小生成树的最大边权,跑 Kruskal 算法,记录一下并查集的大小,当 $siz[y]\ge \frac{n+1}{2}$ 时,输出边权
左图连通块内的格点数 $>5$ 时,已经加完所有点,边权为 5;右图连通块内的格点数 $= 5$ 时,边权为 1

相关板子:
D08【模板】最小生成树 Kruskal 算法 - 董晓 - 博客园
// 最小生成树 Kruskal算法 O(MlogM) #include<bits/stdc++.h> #define int long long using namespace std; const int N=250010,M=N*4; int n,m,tot,ans,mi,a[505][505],fa[N],siz[N]; pair<int,pair<int,int> >e[M]; //边集 int find(int u){ //并查集的找根 return fa[u]==u?u:fa[u]=find(fa[u]); } void kruskal(){ sort(e+1,e+m+1); //排序 for(int i=1; i<=n; i++) fa[i]=i,siz[i]=1; for(int i=1; i<=m; i++){ int x=find(e[i].second.first),y=find(e[i].second.second); if(x!=y){ fa[x]=y; siz[y]+=siz[x]; ans=e[i].first; if(siz[y]>=(n+1)/2) break; } } cout<<ans; } int P(int i,int j){ //给格点编号 return (i-1)*n+j; } signed main(){ cin>>n; for(int i=1;i<=n;i++)for(int j=1;j<=n;++j)cin>>a[i][j]; for(int i=1;i<=n;++i)for(int j=1;j<=n;++j){ if(i>1) e[++m]={abs(a[i][j]-a[i-1][j]),{P(i,j),P(i-1,j)}}; if(j>1) e[++m]={abs(a[i][j]-a[i][j-1]),{P(i,j),P(i,j-1)}}; if(i<n) e[++m]={abs(a[i][j]-a[i+1][j]),{P(i,j),P(i+1,j)}}; if(j<n) e[++m]={abs(a[i][j]-a[i][j+1]),{P(i,j),P(i,j+1)}}; } n*=n; kruskal(); }
浙公网安备 33010602011771号