题解 P3073 【[USACO13FEB]Tractor S】

· · 题解

并查集+最小生成树算法

题目要求最大值最小化,满足最小生成树的性质

Details

1. 建图。除边缘外的每个点均可以向上下左右四个方向连边,点的编号可表示为: n*(i-1)+j (i为行,j为列)

实现代码:

int ex(int i,int j){
    return (i-1)*n+j;
}

边的权值即为两点高度差的绝对值

2. 如何维护集合的大小。初始化将size全设为1,后续再进行合并操作(merge)时,将旧的集合的大小更新到新的集合上。在新的集合大小大于(n*n)/2时,输出当前边的权值即可。

实现代码:

x=find(x);//find函数是为了找父亲
y=find(y);
if(x!=y){
    fa[x]=y;
    siz[y]+=siz[x];
    if(siz[y]>=(n*n+1)/2){
        cout<<w<<endl;
        return 0;
    }
}

3. 最小生成树Kruskal 不解释

不会的可以找模板题P3366 【模板】最小生成树

最后送上代码,祝各位水题切题愉快

#include<bits/stdc++.h>
using namespace std;
const int maxn=501;
int n;
int mp[maxn][maxn];
inline int read(){//快读
    int x=0,y=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')y=-y; ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*y;
}
int fa[maxn*maxn];
int siz[maxn*maxn];
struct node{
    int u,v,w;
    node(){}
    node(int uu,int vv,int ww){
        u=uu;
        v=vv;
        w=ww;
    }
}edge[maxn*maxn*4];
bool cmp(const node &a,const node &b){
    return a.w<b.w;
}
int ans=0;
void init(){
    for(int i=1;i<=n*n;i++){
        fa[i]=i;
        siz[i]=1;
    }
}
int find(int x){
    if(x==fa[x]) return x;
    else return fa[x]=find(fa[x]);
}
int ex(int i,int j){
    return (i-1)*n+j;
}
int main(){
    n=read();
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j){
            mp[i][j]=read();
        }
    }
    init();
    int tp=1;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j){
            if(i>1){
                edge[tp]=node(ex(i,j),ex(i-1,j),abs(mp[i-1][j]-mp[i][j]));
                tp++;
            }
            if(j>1){
                edge[tp]=node(ex(i,j),ex(i,j-1),abs(mp[i][j-1]-mp[i][j]));
                tp++;
            }
            if(i<n){
                edge[tp]=node(ex(i,j),ex(i+1,j),abs(mp[i+1][j]-mp[i][j]));
                tp++;
            }
            if(j<n){
                edge[tp]=node(ex(i,j),ex(i,j+1),abs(mp[i][j+1]-mp[i][j]));
                tp++;
            }
        }
    }
    sort(edge+1,edge+tp,cmp);
    for(int i=1;i<tp;i++){
        int x=edge[i].u;
        int y=edge[i].v;
        int w=edge[i].w;
        x=find(x);
        y=find(y);
        if(x!=y){
            fa[x]=y;
            siz[y]+=siz[x];
            if(siz[y]>=(n*n+1)/2){
                cout<<w<<endl;
                return 0;
            }
        }
    }
}

写题解不易,求个赞