• 洛谷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)
    题目又有要求(lgeqslant 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;
    }
    
  • 相关阅读:
    mysql5.6版本修改密码
    ASP.NET Core MVC 运行所选代码生成器时出错
    abp ef codefirst 设置默认值
    resharper激活
    Ioc(控制反转)、DI(依赖注入)
    统计mysql数据库中数据表/字段等数量的sql
    HeidiSQL安装和使用教程
    mysql的安装步骤
    项目分层的好处
    Python IDLE 的使用与调试
  • 原文地址:https://www.cnblogs.com/Wuzhuoming-sirenboke/p/13620399.html
Copyright © 2020-2023  润新知