06--图2--拯救007【图的表示方法、DFS遍历、C++】

原题链接:点击这里
题目描述
假设该湖泊是100乘100平方的湖泊。
假设湖的中心在 ( 0 , 0 ) (0,0) (0,0),而东北角在 ( 50 , 50 ) (50,50) (50,50)。 中心岛是一个以 ( 0 , 0 ) (0,0) (0,0)为中心的圆盘,直径为15。在湖中的不同位置上有许多鳄鱼。 给定每条鳄鱼的坐标和007可以跳跃的距离,您必须告诉他是否可以逃脱。
拯救007

输入规格
每个输入文件包含一个测试用例。 每种情况都以包含两个正整数 N ( ≤ 100 ) N(≤100) N(100)(鳄鱼的数量)和D(007可以跳跃的最大距离)的行开头。
然后是N行,每行包含一条鳄鱼的 ( x , y ) (x,y) (xy)位置。 请注意,没有两个鳄鱼停留在同一位置。

输出规格
对于每个测试用例,如果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

输出Yes

测试2:

4 13 
-12 12 
12 12 
-12 -12 
12 -12

输出No
思路:

  • 首先对于007,选取每一条鳄鱼所在位置作为节点,首先判断在中心点 ( 0 , 0 ) (0,0) (0,0)的第一跳能跳到的节点有那些 F i r s t J u m p ( i ) 函 数 FirstJump(i)函数 FirstJump(i),对每一个节点做 D F S ( i ) DFS(i) DFS(i)
  • D F S DFS DFS中,查找从 i i i节点能达到的下一节点 j j j ( J u m p ( i , j ) 函 数 Jump(i,j)函数 Jump(i,j)),同时判断能否到岸 I s s a f e ( i ) 函 数 Issafe(i)函数 Issafe(i)
  • 因为这里中心岛到第一个跳出的节点的距离 与 之后节点之间的距离的计算公式不一样,要分开对待
  • 在判断能否到岸的条件,一定不要马虎。步长D >= 节点到岸边的距离(50-|x| 或 50-|y|)因此还存在一个正负坐标转换的问题,有坑
  • 这题还有个值得思考的问题,用什么来保存这个地图的所有节点的坐标呢?这里采用的是结构体数组的方式。非常巧妙。有些时候就是容易钻牛角尖想用邻接矩阵或者邻接表来保存,但其实在此题中,如果这样处理反而变得很麻烦,因此对于图,采用适合的表示方式更好。

参考程序

#include <iostream>
#include <cstring>

using namespace std;
const int maxn=100;
int dfs_vis[maxn];

int N,D;

//用一个结构体数组来保存每个节点的坐标(就是每条鳄鱼所在的坐标)因为鳄鱼最多100条因此定义maxn
struct dex{
       int x;
       int y;
}Point[maxn];

int Jump(int i,int j)
{
    int x1=Point[i].x;
    int y1=Point[i].y;
    int x2=Point[j].x;
    int y2=Point[j].y;
    if(D*D>=((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)))
        return 1;
    else
        return 0;
}
int Issafe(int i)
{
    int e=Point[i].x;
    int f=Point[i].y;
    if(e<0)
        e=~e+1;
    if(f<0)
        f=~f+1;
    if((D>=50-e) || (D>=50-f))
        return 1;
    else
        return 0;
}
int DFS(int i)
{

    dfs_vis[i]=1;
    int ans=0;
    if(Issafe(i))
    {
        ans=1;
    }
    else
    {
        for(int j=0;j<N;j++)
        {
            if(dfs_vis[j]==0 && Jump(i,j))
            {
                ans=DFS(j);
                if(ans==1)
                    break;
            }
        }
    }
    return ans;
}
int FirstJump(int i)
{
    int a=Point[i].x;
    int b=Point[i].y;
    if((7.5+D)*(7.5+D)>=(a*a+b*b))
        return 1;
    else
        return 0;
}
void Save007()
{
    int answer;
    memset(dfs_vis,0,sizeof(0));
    for(int i=0;i<N;i++)
    {
        if(dfs_vis[i]==0 && FirstJump(i))
        {
            answer=DFS(i);
        }
        if(answer==1)
                break;
    }
    if(answer==1)
        cout << "Yes" <<endl;
    else
        cout << "No" <<endl;
}

int main()
{
    cin >> N >>D;
    cin.get();

    for(int i=0;i<N;i++)
    {
        cin >> Point[i].x >> Point[i].y;
        cin.get();
    }
    Save007();
    return 0;
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值