利用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 ...
随机推荐
- BZOJ 3784: 树上的路径 点分治+二分+set
很容易想出二分这个思路,但是要想办法去掉一个 $log$. 没错,空间换时间. 双指针的部分错了好几次~ Code: #include <set> #include <queue&g ...
- 窗体操作:GetWindowLong()
函数原型: LONG GetWindowLong( HWND hWnd,int nIndex ) 参数: hWnd:指定窗口的句柄 nIndex:需要获得的信息的类型 值 ...
- 文件选择对话框:CFileDialog
程序如下: CString FilePathName; //文件名参数定义 CFileDialog Dlg(TRUE,NULL,NULL, ...
- ASE高级软件工程 第一周博客作业
1.自我介绍 我叫姚顺,是来自哈尔滨工业大学计算机学院的一名大四本科生,专业方向计算机科学,目前在KC组实习.平时的业余时间主要用来打篮球,听音乐,跑步,当然还有游戏(划掉).之前的大学三年主要用来做 ...
- python27 错误汇总
一.TypeError: object of type 'NoneType' has no len() 解决的方法: 源代码:resp_data = None (None是一个空的对象) 修改后代码 ...
- 「TJOI2019」唱、跳、rap 和篮球
题目链接 题目分析 据说这是一道生成函数题 看到限制条件,我们首先想到的就是对有多少组讨论cxk的人进行容斥.然后就是求剩下的人随便放有多少种方法了.考虑现在每种剩\(a,b,c,d\)人,还需要排\ ...
- idea maven sync Cannot resolve xxx 的解决方案
经常会出现这种奇葩情况,提示找不到包 其实是因为网络波动或者突然断掉,导致包更新出现问题 直接去maven的仓库目录 找到不能找到的包 删掉相关目录 然后重新更新maven就行了 比如 直接去仓库目录 ...
- Rust Linking With C Library Functions
#[link(name = "c")] extern "C" { fn scanf(format: *const u8, ...); } fn main() { ...
- 问题:解决上传文件IE浏览器弹出下载框bug?
控制器方法的返回值必须以String返回,再由js处理转换成json对象 $.ajaxFileUpload({ url: "/project/proj_conver_upload&quo ...
- DeepWalk 安装指南
DeepWalk 安装指南 创建 conda 虚拟环境 conda create -n deepwalk pip python=3.5 conda activate deepwalk 安装 deepw ...