利用BFS解决拯救007问题 -- 数据结构
题目:
在老电影“007之生死关头”(Live and Let Die)中有一个情节,007被毒贩抓到一个鳄鱼池中心的小岛上,他用了一种极为大胆的方法逃脱 —— 直接踩着池子里一系列鳄鱼的大脑袋跳上岸去!(据说当年替身演员被最后一条鳄鱼咬住了脚,幸好穿的是特别加厚的靴子才逃过一劫。)
设鳄鱼池是长宽为100米的方形,中心坐标为 (0, 0),且东北角坐标为 (50, 50)。池心岛是以 (0, 0) 为圆心、直径15米的圆。给定池中分布的鳄鱼的坐标、以及007一次能跳跃的最大距离,你需要告诉他是否有可能逃出生天。
输入格式:
首先第一行给出两个正整数:鳄鱼数量 N(≤100)和007一次能跳跃的最大距离 D。随后 N 行,每行给出一条鳄鱼的 (x,y) 坐标。注意:不会有两条鳄鱼待在同一个点上。
输出格式:
如果007有可能逃脱,就在一行中输出"Yes",否则输出"No"。
输入样例 1:
14 20
25 -15
-25 28
8 49
29 15
-35 -2
5 28
27 -29
-8 -28
-20 -35
-25 -20
-13 29
-30 15
-35 40
12 12
输出样例 1:
Yes
输入样例 2:
4 13
-12 12
12 12
-12 -12
12 -12
输出样例 2:
No
分析:
1. 首先这看上去是一道图的题目,但实际上是不需要将整个图给存储起来也能够完成题目的要求(当然存起来也可以做),
只需要利用好题目所给的坐标就可了!
2. 值得注意的一点是虽然 N(≤100),但如果化为直观图的话,这是一个 101 * 101 的一个矩阵。
3. 拯救007在这里用DFS和BFS都能够解决,这里采用了BFS算法,下面是整道题的思路:
①从池心岛边缘开始,将能够一步到达的坐标(鳄鱼的位置)入队
记作A集合(红点所示)
②A集合中任意选一个点a(队列首元素出队实现)
判断a点能否一步逃离鳄鱼池:
(1)如果可以,输出 Yes 结束程序
(2)如果不可以,从a开始,将能够一步到达的坐标入队,直至A中所有元素遍历完成。
记作B集合(红点所示)
③B集合重复A集合操作。
循环结束条件:(1)找到符合条件的坐标,输出Yes
(2)遍历所有坐标,无符合条件的,输出No
代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<queue> 5 using namespace std; 6 7 #define max 101 8 9 typedef struct point{ 10 int x, y;//坐标(x,y) 11 double dis;//点point到圆心(0,0)距离 12 }point; 13 14 int visit[max] = {0};//全局变量visit[],记录该坐标是否被访问过 15 void input(point *p, int n); 16 void BFS(point *p, int n, int step); 17 18 int main(){ 19 int n, step; 20 cin>>n>>step; 21 22 point p[max]; 23 memset(p, 0, sizeof(p)); 24 input(p, n); 25 26 //若一步就可以跨出去 27 if(step >= 50-7.5){ 28 cout<<"Yes"; 29 }else BFS(p, n, step);//不能一步就跨出去的话 30 31 return 0; 32 } 33 34 //输入函数:输入数据 35 void input(point *p, int n) 36 { 37 for(int i=0; i<n; i++){ 38 cin>>p[i].x>>p[i].y;//输入鳄鱼的坐标 39 p[i].dis = sqrt(p[i].x*p[i].x + p[i].y*p[i].y) - 7.5;//计算并存储鳄鱼到池心岛的最近距离 40 } 41 } 42 43 //层次遍历 44 void BFS(point *p, int n, int step) 45 { 46 //先将第一步能够够得着的坐标入队列 47 queue<point> qu; 48 for(int i=0; i<n; i++){ 49 if(p[i].dis<=step){ 50 qu.push(p[i]); 51 visit[i] = 1; 52 } 53 } 54 55 while(qu.size() != 0){ 56 //判断出队的点A下一步能不能够跨出去 57 point mark = qu.front(); 58 if(mark.x+step >= 50 || mark.x-step <= -50 || mark.y+step >=50 || mark.y-step <=-50){ 59 cout<<"Yes"; 60 return; 61 } 62 qu.pop(); 63 64 // A点下一步能够够得着的点入队 65 for(int i=0; i<n; i++){ 66 if(visit[i] != 1 && sqrt((mark.x-p[i].x)*(mark.x-p[i].x) + (mark.y-p[i].y)*(mark.y-p[i].y)) <= step){ 67 qu.push(p[i]); 68 //入队标记 69 visit[i] = 1; 70 } 71 } 72 } 73 74 cout<<"No"; 75 76 }
总结:
拯救007这个题目是一道很好的拓展眼界的题目吧,刚接触这道题的时候会被课本的知识限制住了想象空间,
总觉得做图的题目都要先将图给存储起来,才好做下一步的操作。
还是学的太少,被自己的知识绊住了脚步。
:D 加油!