利用Kruskal算法求最小生成树解决聪明的猴子问题 -- 数据结构
题目:聪明的猴子
链接:https://ac.nowcoder.com/acm/problem/19964
输入描述:
第1行为一个整数,表示猴子的个数M(2 ≤ M ≤ 500);
第2行为M个整数,依次表示猴子的最大跳跃距离(每个整数值在1--1000之间);
第3行为一个整数表示树的总棵数N(2 ≤ N ≤ 1000);
第4行至第N+3行为N棵树的坐标(横纵坐标均为整数,范围为:-1000--1000)。(同一行的整数间用空格分开)
输出描述:
包括一个整数,表示可以在这个地区的所有树冠上觅食的猴子数
输入
4
1 2 3 4
6
0 0
1 0
1 2
-1 -1
-2 0
2 2
输出
3
分析: 1.题目中的树冠上觅食的猴子数是指能够在所有树上自由移动的猴子数; 2.为了解决这一道题,我们应该要求出最小生成树中最长边的大小,再用每个猴子能够移动的最大距离逐一比较; 3.这里我将采用Kruskal算法求最小生成树:
①将所有边按权值排序(以升序为例)
②按照边的排序构建最小生成树
代码: 1.顶点结构定义:
typedef struct point{
int x, y;//坐标(x,y)
bool status;
}point;
2.边结构定义:
typedef struct edge{
point p1, p2;//边的两个端点
double weight;//边的权值
}edge;
3.对edge e[]进行升序排序:
//按权值快速排序
qsort(e, tree_num*(tree_num-)/, sizeof(edge), cmp);
//cmp函数
int cmp(const void *a, const void *b)
{
return (*(edge *)a).weight > (*(edge *)b).weight ? : -;
}
4.Kruskal函数
/*传入:
edge *e 存放边的数组
int tree_num 树的数量
point *p 存放点的数组
*/ double kruskal(edge *e, int tree_num, point *p)
{
//并查集
int v[tree_num];
for(int i=; i<tree_num; i++){
v[i] = i;
} double longest; int i1, i2;
for(int i=; i<tree_num*(tree_num-)/; i++){
if(search(p, e[i].p1, tree_num) == - || search(p, e[i].p2, tree_num) == -){
exit(-);//ERROR:没有找到e[i].p1在p[]中的坐标
}
//serach()查找 e[i].p1在p[]中的坐标
i1 = v[search(p, e[i].p1, tree_num)];
i2 = v[search(p, e[i].p2, tree_num)]; if(i1 == i2 == tree_num-)break;//已经构建成最小生成树
if(i1 == i2)continue;//边的两个端点已经在同一个集合中 //将i1,i2中较大的作为标记
int i3 = i1>i2 ? i1:i2;
for(int j=; j<tree_num; j++){
if(v[j] == i1 || v[j] == i2){
v[j] = i3;
}
}
longest = e[i].weight;//更新长边
}
return longest;//返回最长边
}
5.search函数(Kruskal函数中调用):
int search(point *p, point p1, int tree_num)
{
for(int i=; i<tree_num; i++){
if(p1.x == p[i].x && p1.y == p[i].y){
return i;
}
}
return -;
}
6.所有代码:
#include<iostream>
#include<cmath>
#include<cstring>
#include <stdlib.h>
using namespace std; #define max 1000 typedef struct point{
int x, y;//坐标(x,y)
bool status;
}point; typedef struct edge{
point p1, p2;//边的两个端点
double weight;//边的权值
}edge; int cmp( const void *a ,const void *b);
double kruskal(edge *e, int tree_num, point *p);
int get_root(int *v, int x);
int search(point *p, point p1, int tree_num);
int main(){
//输入猴子数量
int monkey_num;
cin>>monkey_num; //输入猴子能到达的最远距离
int step[monkey_num];
memset(step, , sizeof(step));
for(int i=; i<monkey_num; i++){
cin>>step[i];
} //输入树的数量
int tree_num;
cin>>tree_num; //输入树的坐标(点记录)
point p[max];
memset(p, , sizeof(p));
for(int i=; i<tree_num; i++){
cin>>p[i].x>>p[i].y;
p[i].status = ;//status为1表示可操作的树
} //边记录
edge e[max];
int t = ;
int vi[max] = {};
for(int i=; p[i].status != ; i++){
for(int j=; p[j].status != ; j++){
if(i != j && vi[j] == ){//增加边的权值,两个端点
e[t].weight = sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x) + (p[i].y-p[j].y)*(p[i].y-p[j].y));
e[t].p1 = p[i];
e[t++].p2 = p[j];
}
}
vi[i] = ;//标记p[i]点连接的所有边已经被读取
} //按权值快速排序
qsort(e, tree_num*(tree_num-)/, sizeof(edge), cmp); double longest = kruskal(e, tree_num, p); int ans = ;
for(int i=; i<monkey_num; i++){
if(step[i] >= longest)ans++;
}
cout<<ans; return ;
} int cmp(const void *a, const void *b)
{
return (*(edge *)a).weight > (*(edge *)b).weight ? : -;
} double kruskal(edge *e, int tree_num, point *p)
{
//并查集
int v[tree_num];
for(int i=; i<tree_num; i++){
v[i] = i;
} double longest; int i1, i2;
for(int i=; i<tree_num*(tree_num-)/; i++){
if(search(p, e[i].p1, tree_num) == - || search(p, e[i].p2, tree_num) == -){
exit(-);//ERROR:没有找到e[i].p1在p[]中的坐标
}
//serach()查找 e[i].p1在p[]中的坐标
i1 = v[search(p, e[i].p1, tree_num)];
i2 = v[search(p, e[i].p2, tree_num)]; if(i1 == i2 == tree_num-)break;//已经构建成最小生成树
if(i1 == i2)continue;//边的两个端点已经在同一个集合中 //将i1,i2中较大的作为标记
int i3 = i1>i2 ? i1:i2;
for(int j=; j<tree_num; j++){
if(v[j] == i1 || v[j] == i2){
v[j] = i3;
}
}
longest = e[i].weight;
}
return longest;
} int search(point *p, point p1, int tree_num)
{
for(int i=; i<tree_num; i++){
if(p1.x == p[i].x && p1.y == p[i].y){
return i;
}
}
return -;
}
ALL
总结:
很多时候还是听懂容易实践难,难就难在为了实现功能要有一层一层缜密的逻辑需要构建,漏了一种情况都会影响结果的。 (外面的oj真的很严格呢)

参考资料: 【算法】图的最小生成树(Kruskal算法)
利用Kruskal算法求最小生成树解决聪明的猴子问题 -- 数据结构的更多相关文章
- 克鲁斯卡尔(Kruskal)算法求最小生成树
/* *Kruskal算法求MST */ #include <iostream> #include <cstdio> #include <cstring> #inc ...
- Prim算法和Kruskal算法求最小生成树
Prim算法 连通分量是指图的一个子图,子图中任意两个顶点之间都是可达的.最小生成树是连通图的一个连通分量,且所有边的权值和最小. 最小生成树中,一个顶点最多与两个顶点邻接:若连通图有n个顶点,则最小 ...
- Prime算法 与 Kruskal算法求最小生成树模板
算法原理参考链接 ==> UESTC算法讲堂——最小生成树 关于两种算法的复杂度分析 ==> http://blog.csdn.net/haskei/article/details/531 ...
- kruskal算法求最小生成树(jungle roads的kruskal解法)
注意: 注意数组越界问题(提交出现runtimeError代表数组越界) 刚开始提交的时候,边集中边的数目和点集中点的数目用的同一个宏定义,但是宏定义是按照点的最大数定义的,所以提交的时候出现了数组越 ...
- Kruskal算法求最小生成树
Kruskal算法是根据权来筛选节点,也是采用贪心算法. /// Kruskal ///初始化每个节点为独立的点,他的祖先为自己本身 void made(int n) { ; i<=n; i++ ...
- 859. Kruskal算法求最小生成树(模板)
给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数. 求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible. 给定一张边带权的无向图G=(V, E),其中V表示 ...
- Kruskal算法求最小生成树 笔记与思路整理
整理一下前一段时间的最小生成树的算法.(其实是刚弄明白 Kruskal其实算是一种贪心算法.先将边按权值排序,每次选一条没选过的权值最小边加入树,若加入后成环就跳过. 先贴张图做个示例. (可视化均来 ...
- Kruskal算法求最小生成树(POJ2485)
题目链接:http://poj.org/problem?id=2485 #include <iostream> #include <stdio.h> #include < ...
- AcWing 859. Kruskal算法求最小生成树 稠密图
//稠密图 #include <cstring> #include <iostream> #include <algorithm> using namespace ...
随机推荐
- python 正则表达式实例
字符匹配 实例 描述 python 匹配 "python". 字符类 实例 描述 [Pp]ython 匹配 "Python" 或 "python&qu ...
- IE大文件断点续传
IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag 客户端每次提交下载请求时,服务 ...
- 「CQOI2014」数三角形
题目链接 问题分析 可以先任意选\(3\)个数,然后减去三点共线的部分. 三点共线又分\(2\)种情况: 横的或者竖的.这一部分方案数是\(n\times{m\choose 3}+m\times {n ...
- 兼容pc端和移动端的轮播图插件 swiper.js
swiper.js是一款纯JavaScript打造的滑动特效插件,可以用来实现检点轮播图,tab触摸滑动切换等常用效果.下载地址:https://www.swiper.com.cn/download/ ...
- linux下安装R第三方包forecast
ERROR: [root@localhost soft]# R CMD INSTALL curl_3.1.tar.gz WARNING: ignoring environment value of R ...
- SQLite索引
索引(Index)是一种特殊的查找表,数据库搜索引擎用来加快数据检索.简单地说,索引是一个指向表中数据的指针.一个数据库中的索引与一本书后边的索引是非常相似的. 例如,如果您想在一本讨论某个话题的书中 ...
- log4j动态配置参数
特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...
- How does ASP.NET Forms Authentication really work?
I've always wondered how exactly ASP.NET forms authentication works. Yes, I know how to configure Fo ...
- Docker—备份、恢复及迁移
用容器生成镜像 [root@git docker]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e950a988d ...
- 联想笔记本安装乌班图16.04无法连接WIFI的问题
来自大佬微博 https://www.cnblogs.com/carious/p/9580344.html