拯救007
在老电影“007之生死关头”(Live and Let Die)中有一个情节,007被毒贩抓到一个鳄鱼池中心的小岛上,他用了一种极为大胆的方法逃脱 —— 直接踩着池子里一系列鳄鱼的大脑袋跳上岸去!(据说当年替身演员被最后一条鳄鱼咬住了脚,幸好穿的是特别加厚的靴子才逃过一劫。)
设鳄鱼池是长宽为100米的方形,中心坐标为 (0, 0),且东北角坐标为 (50, 50)。池心岛是以 (0, 0) 为圆心、直径15米的圆。给定池中分布的鳄鱼的坐标、以及007一次能跳跃的最大距离,你需要告诉他是否有可能逃出生天。
输入格式:
首先第一行给出两个正整数:鳄鱼数量 N(≤)和007一次能跳跃的最大距离 D。随后 N 行,每行给出一条鳄鱼的 ( 坐标。注意:不会有两条鳄鱼待在同一个点上。
输出格式:
如果007有可能逃脱,就在一行中输出"Yes",否则输出"No"。
输入样例 2:
4 13
-12 12
12 12
-12 -12
12 -12
输出样例 2:
No
第一次看到这题的时候在想会不会是最小生成树的知识,在一个顶点上选择能够跳过去的点(距离就是权值)这不就有点像选点法吗,然后一直往里面想,但后来发现不太对劲,因为它好像只是在一个点上选择能跳的点的其中一个然后判断能否到达边缘,如果可以就直接结束输出yes,如果还没不能到达边缘就继续找下一个能跳的点,如果当前所在的顶点周围都没有可以跳的点(就是说这一条路已经到尽头了不能再走下去了)就返回上一个点再重新选一个可以跳的点,直到所有的路径都试过都不行就输出no,其实就是简单的深度搜索(到尽头返回上一层从另一个邻接点出发)。
输入的数据其实很简单,顶点数加上能跳的距离+逐个输入每个顶点的坐标。我们就可以用一个结构体数组来接收坐标信息,二维数组应该也可以的吧。
但是这里要注意的是第一次跳跃的点和其他能跳的点的判断不同哦,因为第一次跳的时候还要算上岛的半径才行,同时如果第一次就没有能跳的点那么程序就可以直接结束输出no啦。让我们废话不多说赶快开始吧。
先来主函数:接收输入数据,统计一下第一次能跳过去的点有多少个,然后就以这么多个点为起点逐一沿着可行路径走下去(就是深度搜索下去)。
int main() { int num=0; int first[max]; danger ori; cin>>n>>l; for(int i=0;i<n;i++) {//接收输入数据 cin>>p[i].x>>p[i].y; } ori.x=ori.y=0; for(int i=0;i<n;i++) {//首先先算一下第一次能跳的点有多少个 if(dis(p[i],ori)<=l+7.5) { first[num++]=i; } } if(num==0) {//如果第一次都没有可以跳的点就直接是no了 cout<<"No"; return 0; } for(int i=0;i<num;i++) {//否则就从这么点开始试试每一条路径 DFS(first[i]); } cout<<"No";
补充计算返回两点距离的函数:这里用了平方根函数sqrt()和求n次方的函数pow(a,n次方)。注意添加头文件cmath(pow)还有cstdio(sqrt)。这里我打的时候出现了一个问题,就是编译的时候显示stl_iterator_base_types中报错,我一直不知道为什么上网查了一下也没有找到相应的问题,但后来看到有人说是命名空间的问题(命名空间不是就是std吗)然后我突然想到函数名了,果真把distance改掉就可以了。
double dis(danger a,danger b) {//计算两个点之间的距离,注意添加头文件 return sqrt(pow((a.x-b.x),2)+pow((a.y-b.y),2)); }
接着就是最重要的DFS函数:先标记下这个点我已经来过啦,如果当前的这个点已经可以跳到边缘上就可以输出yes然后程序就结束啦,如果还不行就继续寻找下一个没去过的点而且是可以到达的点,跳到那个点之后再重新以那个点为新的起点来判断啊什么的(就是用递归的方法)。
void DFS(int v) {//就是dfs遍历 visit[v]=true;//已经走过这个点就标记一下 if(abs(50-p[v].x)<=l || abs(50-p[v].y)<=l) { //如果这个点到边缘的距离是可以跳过去的(往上下左右方向,不是点到点的距离哦) cout<<"Yes"; exit(0) ;//程序结束输出yes } else {//否则就找下一个能跳的点 for(int i=0;i<n;i++) {//所有的点都遍历一遍 if(!visit[i] && (dis(p[i],p[v])<=l)) DFS(i); //如果有顶点没去过而且还可以跳过去的话就从那个点开始重新找下一个点 } } }
最后就是补充上一些全局变量,标记的数组visit+结构体数组+输入的点数还有能跳的距离
struct danger { int x,y; };//定义一个结构体存放每个顶点的坐标 danger p[max]; //定义一个结构体数组来存放所有的点 bool visit[max]={false}; //定义一个全局变量来记录每个点是否已经去过 int n,l;
好了,整道题就完成了
#include <iostream> #include <cstdio> #include <cmath> #define max 102 using namespace std; struct danger { int x,y; };//定义一个结构体存放每个顶点的坐标 danger p[max]; //定义一个结构体数组来存放所有的点 bool visit[max]={false}; //定义一个全局变量来记录每个点是否已经去过 int n,l; double dis(danger a,danger b) {//计算两个点之间的距离,注意添加头文件 return sqrt(pow((a.x-b.x),2)+pow((a.y-b.y),2)); } void DFS(int v) {//就是dfs遍历 visit[v]=true;//已经走过这个点就标记一下 if(abs(50-p[v].x)<=l || abs(50-p[v].y)<=l) { //如果这个点到边缘的距离是可以跳过去的(往上下左右方向,不是点到点的距离哦) cout<<"Yes"; exit(0) ;//程序结束输出yes } else {//否则就找下一个能跳的点 for(int i=0;i<n;i++) {//所有的点都遍历一遍 if(!visit[i] && (dis(p[i],p[v])<=l)) DFS(i); //如果有顶点没去过而且还可以跳过去的话就从那个点开始重新找下一个点 } } } int main() { int num=0; int first[max]; danger ori; cin>>n>>l; for(int i=0;i<n;i++) {//接收输入数据 cin>>p[i].x>>p[i].y; } ori.x=ori.y=0; for(int i=0;i<n;i++) {//首先先算一下第一次能跳的点有多少个 if(dis(p[i],ori)<=l+7.5) { first[num++]=i; } } if(num==0) {//如果第一次都没有可以跳的点就直接是no了 cout<<"No"; return 0; } for(int i=0;i<num;i++) {//否则就从这么点开始试试每一条路径 DFS(first[i]); } cout<<"No"; }