Live2D

洛谷P2212 [USACO14MAR]Watering the Fields S

题目链接:洛谷P2212[USACO14MAR]Watering the Fields S
最小生成树
Kruskal算法:
算法详情见最小生成树(kruskal算法)
此题其实用kruskal和prim都是可以的,本人认为kruskal更好打一些所以选择了kruskal
我们先来看一下题目:
有n个点,给出每一个点的坐标(\(x_i\),\(y_i\)
这样我们可以求出每一对点之间的距离:l = \((x_i-x_j)^2\) + \((y_i-y_j)^2\)
题目又有要求\(l\geqslant c\)所以我们可以判断一下是否满足要求然后再加入e数组
将e数组排个序,然后跑一遍kruskal,求出最小生成树的总边权
最后输出答案
别忘了特判:选择的边的数量一定要等于n - 1
现在来看一下代码(附赠注释):

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int read() {
	int w = 1,res = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
	while(ch >= '0' && ch <= '9') res = res * 10 + ch - '0', ch = getchar();
	return w * res;
}                             //快读没啥好说
int x[2010], y[2010], m, c, n;//x为点的横坐标,y为点的纵坐标,m为边的总数,c,n如题意
long long ans = 0;            //答案记录
struct Edge {
	int from, to;
	long long w;
} e[10000010];  //存储边的信息
int pf(int x) { //平方
	return x * x;
}

bool cmp(Edge a, Edge b) { //排序用的比较函数
	return a.w < b.w;
}

int pre[2010];   //并查集父亲数组
int find(int k) {//‘查’+路径压缩
	return pre[k] == k ? k : pre[k] = find(pre[k]);
}

void kruskal() {                                             //kruskal算法
	int edge_num = 0;
	sort(e + 1, e + m + 1, cmp);                         //将边按大小排序
	for(int i = 1; i <= m; i ++) {
		if(edge_num == n - 1) break;                 //如果已经有了n-1条边,那么直接退出循环
		if(find(e[i].from) != find(e[i].to)) {
			pre[find(e[i].to)] = find(e[i].from);//并
			ans += e[i].w;                       //总边权加上那一条边的边权
			edge_num ++;                         //选择的边数要加一
		}
	}
	if(edge_num < n - 1) ans = -1;                       //如果没有选择够n-1条边,说明这张图还不是树,ans=-1
}
int main() {
	n = read(), c = read(), m = 0;
	for(int i = 1; i <= n; i ++)
		x[i] = read(), y[i] = read(), pre[i] = i;//记得初始化
	for(int i = 1; i <= n; i ++) 
		for(int j = i + 1; j <= n; j ++) {
			long long l = pf(x[i] - x[j]) + pf(y[i] - y[j]);//计算边的长度
			if(l < c) continue;                             //如果边的长度小于c就直接continue
			e[++ m].from = i;
			e[m].to = j;
			e[m].w = l; //加边操作
		}
	if(m < n - 1) {             //如果总边数都小于n-1,直接输出-1
		cout << -1;
		return 0;
	}
	kruskal();
	cout << ans;
	return 0;
}
posted @ 2020-09-06 00:21  Wuzhouming  阅读(118)  评论(0编辑  收藏  举报