Watering the field(并查集、Kruskal)

Description
农民约翰想建立一个灌溉系统,给他的N (1 <= N<= 2000)块田送水。农田在一个二维平面上,第i块农田坐标为(xi​ , yi​ )(0 <= xi​ , yi​<= 1000),在农田 i 和农田 j 自己铺设水管的费用是这两块农田的欧几里得距离的平方(xi−xj)^2 + (yi−yj)^2。

农民约翰希望所有的农田之间都能通水,而且希望花费最少的钱。但是安装工人拒绝安装费用小于C的水管(1 <= C<=1,000,000)。

请帮助农民约翰建立一个花费最小的灌溉网络,如果无法建立请输出-1。

Input
Line 1: The integers N and C.
Lines 2 N~ N+1: Line i+1 contains the integers xi​ and yi​.

Output
Line 1: The minimum cost of a network of pipes connecting the fields, or −1 if no such network can be built.

分析:“所有农田之间都能通水”即图连通,水管的费用可视为边权,“希望花费最少的钱”即求最小生成树。本题中任意两块农田之间皆可铺设水管,即任意两块农田之间皆有路,则本题需要自行建立一张以农田为节点、欧几里得距离平方为边权的完全图

AC代码:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>

struct EDGE
{
    
    
    int u;
    int v;
    int val;
    friend bool operator<(EDGE &e1,EDGE &e2)
    {
    
    
        return e1.val<e2.val;
    }
}edge[4000010];

int dot[2010][2];//记录农田坐标
int parent[2010];
int rank[2010];
long long ans=0;//记录费用
int sum=0;//记录已选边数
int n,m=0;//点数,边数
int c;//单根水管价格下限

inline void initialize()
{
    
    
    for(int i=0;i<n;++i)
    {
    
    
        parent[i]=i;
    }
    memset(rank,0,sizeof(rank));
}

int find_root(int x)
{
    
    
    int x_root=x;
    while(parent[x_root]!=x_root)
        x_root=parent[x_root];
    return x_root;
}

int union_vertices(int x,int y)
{
    
    
    int x_root=find_root(x);
    int y_root=find_root(y);

    if(x_root==y_root) return 0;

    if(rank[x_root]>rank[y_root]) parent[y_root]=x_root;
    else if(rank[x_root]<rank[y_root]) parent[x_root]=y_root;
    else {
    
    parent[x_root]=y_root;++rank[y_root];}
    return 1;
}

int main()
{
    
    
    scanf("%d%d",&n,&c);
    for(int i=0;i<n;++i)
    {
    
    
        scanf("%d%d",&dot[i][0],&dot[i][1]);
    }
    for(int i=0;i<n;++i)//建完全图
    {
    
    
        for(int j=i+1;j<n;++j)
        {
    
    
            edge[m].u=i;
            edge[m].v=j;
            edge[m++].val=pow(dot[i][0]-dot[j][0],2)+pow(dot[i][1]-dot[j][1],2);
        }
    }
    std::sort(edge,edge+m);
    initialize();
    for(int i=0;i<m;++i)
    {
    
    
        if(edge[i].val<c) continue;
        if(union_vertices(edge[i].u,edge[i].v))
        {
    
    
            ans+=edge[i].val;
            ++sum;
        }
        if(sum==n-1) break;
    }
    if(sum<n-1) printf("-1");
    else printf("%d",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44643644/article/details/108691278