[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;
}

完结撒花!

posted @ 2020-05-22 22:48  qzwer  阅读(137)  评论(0编辑  收藏  举报