最小生成树-Magicpig密室出逃(Kruskal+并查集)
文章目录
- Kruskal算法
- 题目
- 分析
- 代码
- 小结
Kruskal算法
Kruskal算法是按边权从小到大依次加入边,如果某次加边产生了环(并查集判断),就扔掉这条边,直到加入了n-1条边,即形成了一棵树。
题目
在金字塔中有一个叫Room-of-No-Return 的大房间,非常不幸的是Magicpig现在被困在这个房间里。房间的地板上有一些钩子。在房间的墙上有一些古老的埃及文字:“如果你想逃离这里,你必须用绳索连接所有这些钩子,然后一个秘密的门将打开,你将获得自由。如果你不能这样做,你将永远被困在这里”。幸运的是Magicpig有一条长度为L的绳索,他可以把它切成段,每段可以连接两个钩子,如果他能用这段绳子连接所有钩子,并且连接的绳子不能出现环路,就可以成功逃脱!Kinfkong想知道他是否可以逃跑。
输入格式:
输入包含一个或多个数据集。在每个输入数据集的第1行有两个整数n和L,其中n是钩子的数量,L是绳索的长度。接下来的n行包含钩子的一系列坐标,每个坐标是一个非负整数对,并且每个整数小于32768,每对都用空格分隔(2<=n<=100,L<=32767)。钩子的数量n 为零表示输入结束。
输出格式:
对于每个数据集,如果Magicpig可以逃脱,打印一个字符串”Success!”,否则打印“Poor magicpig!”.
输入样例:
2 1
0 0
1 1
2 2
0 0
1 1
0
输出样例:
Poor magicpig!
Success!
分析
首先准备工作把题目读入的坐标,构建成完全连通图,得到边(两点距离公式)。 然后就是套用Krusakal算法,先对边排序,遍历每次选最小的边,然后用并查集判断它的两个端点是否在一个集合,不是的话则加入该边,更新花费和并操作。 最后返回花费和绳索长度比较即可。
代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 102
int n, m;
int cnt;//边数
int root[maxn];
struct node {
int x, y;//坐标
int idx;//下标
}points[maxn];
struct node2 {
int u, v;//端点
double cost;//权值
}edge[maxn*maxn];
bool cmp(node2 a, node2 b) {
return a.cost < b.cost;
}
int Find(int x) {
return root[x] == x ? x : root[x] = Find(root[x]);
}
double Kruskal() {
for (int i = 0; i <= n; i++)
root[i] = i;
sort(edge + 1, edge + cnt, cmp);
double ans = 0;
for (int i = 1; i <= cnt; i++) {
int u = Find(edge[i].u);
int v = Find(edge[i].v);
if (u != v) {
root[u] = v;//Union
ans += edge[i].cost;
}
}
//判断非连通图
return ans;
}
int main() {
while (~scanf("%d", &n) && n != 0) {
scanf("%d", &m);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &points[i].x, &points[i].y);
points[i].idx = i;
}
cnt = 1;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
edge[cnt].u = points[i].idx;
edge[cnt].v = points[j].idx;
double cost = pow(points[i].x - points[j].x, 2);
cost += pow(points[i].y - points[j].y, 2);
cost = sqrt(cost);
edge[cnt].cost = cost;
cnt++;
}
}
double ans = Kruskal();
if (ans > m)printf("Poor magicpig!n");
else printf("Success!n");
}
return 0;
}
小结
- 一般Kruskal算法最后还要判断构建出来的图是否为连通图,由于本题把坐标两两求边得到完全连通图便省略。
- 图的存储问题:若邻接矩阵超限,考虑邻接表(vector实现)。
原创不易,请勿转载(
本不富裕的访问量雪上加霜) 博主首页:https://blog.csdn.net/qq_45034708
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android 天气APP(二十四)地图天气(上)自动定位和地图点击定位
- 3分钟短文:可能是Laravel模板最直白的用法了,没有之一
- Android 天气APP(二十三)增加灾害预警、优化主页面UI
- Android 天气APP(二十一)滑动改变UI、增加更多天气数据展示,最多未来15天天气预报
- Android 读取csv格式数据文件
- Android LitePal的简单使用
- Android RecyclerVIew列表使用 (编辑、单选、全选、删除、动画效果+附源码)
- Android TV 焦点控制
- Kotlin学习日志(四)函数
- Kotlin学习日志(三)控制语句
- Kotlin学习日志(一)TextView、Button、Toast的使用
- Kotlin学习日志(二)数据类型
- Toast提示工具类
- RadioGroup+ViewPager +Fragment 制作APP主界面底部导航和左右滑动
- MD5加密工具类