[USACO14MAR]浇地Watering the Fields
题目传送门
这题可以用最小生成树来写,一道Kruskal裸题 虽然我TLE了很多遍,(数组开大了)
Kruskal简单易懂,代码清爽 时间复杂度\(O(mlogm)\)
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int f[2010],x[2010],y[2010];//f为father,x,y为坐标
struct node{
int x,y,len;
}a[10000000];//数组要开大点
bool cmp(node x,node y){return x.len<y.len;}//边权值从小到大排序
inline int ojld(int x1,int x2,int y1,int y2){return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);}//计算欧几里得距离
int find(int x){
while(x!=f[x])x=f[x]=f[f[x]];
return x;
}//找祖先
int sum;
void kruskal(){//Kruskal模板
int t=0,ans=0;
sort(a+1,a+sum+1,cmp);//排序
for(int i=1;i<=n;i++)f[i]=i;//初始化,把father定义为自己
for(int i=1;i<=sum;i++){
int faa=find(a[i].x);
int fbb=find(a[i].y);
if(faa!=fbb){//如果祖先不一样
f[faa]=fbb;
ans+=a[i].len;//加上边权值
t++;
}
if(t==n-1)break;//如果与n-1条边相等,退出循环
}
if(t==n-1)printf("%d",ans);
else puts("-1");//记得特判~
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d %d",&x[i],&y[i]);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++){
int d=ojld(x[i],x[j],y[i],y[j]);
if(d>=m)
sum++,a[sum].x=i,a[sum].y=j,a[sum].len=d;//如果两个农田距离大于m,存起来
}
kruskal();
return 0;
}
完结撒花!