洛谷P2212 [USACO14MAR]浇地Watering the Fields(kruskal)

孤街浪徒 提交于 2020-01-30 01:24:40

洛谷P2212
题目大概意思是有n块田地,给出坐标xi,yi,铺设两块田地之间水管的费用为两点间距离的平方,水管工人只铺设费用大于等于c的水管,问是否能将n块田地连通,如果可以输出最小费用,如果不行输出-1.

kruskal做法
很显然是个板子题,我们只需要把费用大于等于c的边加进去就行,然后遍历所有边,看是否能形成连通图,如果能就输出费用即可。
注意由于数据较大,建边的时候每对点建一条边即可,不然TLE on test 9。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const double EPS=1e-6;
typedef long long ll;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int x[N],y[N];
int fa[N],sizes[N];
int dis(int i,int j)
{
    return (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
}
struct node
{
    int x,y,dis;
}e[5000010];
int tot=0;
void addedge(int u,int v)
{
    tot++;
    e[tot].x=u;
    e[tot].y=v;
    e[tot].dis=dis(u,v);
}
bool cmp(node a,node b)
{
    return a.dis<b.dis;
}
int find(int x)
{
    if(x==fa[x])
        return x;
    return fa[x]=find(fa[x]);
}
int main()
{
    IOS;
    int n,c;
    cin>>n>>c;
    for(int i=1;i<=n;i++)
        fa[i]=i,sizes[i]=1;
    for(int i=1;i<=n;i++)
    {
        cin>>x[i]>>y[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            if(i!=j)
            {
                if(dis(i,j)>=c)
                {
                    addedge(i,j);
                }
            }
        }
    }
    sort(e+1,e+tot+1,cmp);
    int cnt=n;
    ll sum=0;
    for(int i=1;i<=tot;i++)
    {
        if(cnt==1)
        {
            break;
        }
        int xx=find(e[i].x);
        int yy=find(e[i].y);
        if(xx!=yy)
        {
            if(sizes[xx]>=sizes[yy])
            {
                fa[yy]=xx;
                sizes[xx]+=sizes[yy];
            }
            else
            {
                fa[xx]=yy;
                sizes[yy]+=sizes[xx];
            }
            sum+=e[i].dis;
            cnt--;
        }
    }
    if(cnt==1)
        cout<<sum;
    else
        cout<<-1;
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!