标签:现在 show fine get ble 分析 构建 整数 集合
题目:聪明的猴子
链接: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-1)/2, sizeof(edge), cmp);
//cmp函数 int cmp(const void *a, const void *b) { return (*(edge *)a).weight > (*(edge *)b).weight ? 1 : -1; }
4.Kruskal函数
1 /*传入: 2 edge *e 存放边的数组 3 int tree_num 树的数量 4 point *p 存放点的数组 5 */ 6 7 double kruskal(edge *e, int tree_num, point *p) 8 { 9 //并查集 10 int v[tree_num]; 11 for(int i=0; i<tree_num; i++){ 12 v[i] = i; 13 } 14 15 double longest; 16 17 int i1, i2; 18 for(int i=0; i<tree_num*(tree_num-1)/2; i++){ 19 if(search(p, e[i].p1, tree_num) == -1 || search(p, e[i].p2, tree_num) == -1){ 20 exit(-1);//ERROR:没有找到e[i].p1在p[]中的坐标 21 } 22 //serach()查找 e[i].p1在p[]中的坐标 23 i1 = v[search(p, e[i].p1, tree_num)]; 24 i2 = v[search(p, e[i].p2, tree_num)]; 25 26 27 if(i1 == i2 == tree_num-1)break;//已经构建成最小生成树 28 if(i1 == i2)continue;//边的两个端点已经在同一个集合中 29 30 //将i1,i2中较大的作为标记 31 int i3 = i1>i2 ? i1:i2; 32 for(int j=0; j<tree_num; j++){ 33 if(v[j] == i1 || v[j] == i2){ 34 v[j] = i3; 35 } 36 } 37 longest = e[i].weight;//更新长边 38 } 39 return longest;//返回最长边 40 }
5.search函数(Kruskal函数中调用):
int search(point *p, point p1, int tree_num) { for(int i=0; i<tree_num; i++){ if(p1.x == p[i].x && p1.y == p[i].y){ return i; } } return -1; }
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, 0, sizeof(step)); for(int i=0; i<monkey_num; i++){ cin>>step[i]; } //输入树的数量 int tree_num; cin>>tree_num; //输入树的坐标(点记录) point p[max]; memset(p, 0, sizeof(p)); for(int i=0; i<tree_num; i++){ cin>>p[i].x>>p[i].y; p[i].status = 1;//status为1表示可操作的树 } //边记录 edge e[max]; int t = 0; int vi[max] = {0}; for(int i=0; p[i].status != 0; i++){ for(int j=0; p[j].status != 0 ; j++){ if(i != j && vi[j] == 0){//增加边的权值,两个端点 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] = 1;//标记p[i]点连接的所有边已经被读取 } //按权值快速排序 qsort(e, tree_num*(tree_num-1)/2, sizeof(edge), cmp); double longest = kruskal(e, tree_num, p); int ans = 0; for(int i=0; i<monkey_num; i++){ if(step[i] >= longest)ans++; } cout<<ans; return 0; } int cmp(const void *a, const void *b) { return (*(edge *)a).weight > (*(edge *)b).weight ? 1 : -1; } double kruskal(edge *e, int tree_num, point *p) { //并查集 int v[tree_num]; for(int i=0; i<tree_num; i++){ v[i] = i; } double longest; int i1, i2; for(int i=0; i<tree_num*(tree_num-1)/2; i++){ if(search(p, e[i].p1, tree_num) == -1 || search(p, e[i].p2, tree_num) == -1){ exit(-1);//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-1)break;//已经构建成最小生成树 if(i1 == i2)continue;//边的两个端点已经在同一个集合中 //将i1,i2中较大的作为标记 int i3 = i1>i2 ? i1:i2; for(int j=0; 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=0; i<tree_num; i++){ if(p1.x == p[i].x && p1.y == p[i].y){ return i; } } return -1; }
总结:
很多时候还是听懂容易实践难,难就难在为了实现功能要有一层一层缜密的逻辑需要构建,漏了一种情况都会影响结果的。
(外面的oj真的很严格呢)
参考资料:
【算法】图的最小生成树(Kruskal算法)
利用Kruskal算法求最小生成树解决聪明的猴子问题 -- 数据结构
标签:现在 show fine get ble 分析 构建 整数 集合
原文地址:https://www.cnblogs.com/yi2105/p/10888329.html