浙大数据结构第六周之Saving James Bond - Easy Version

题目详情:

This time let us consider the situation in the movie "Live and Let Die" in which James Bond, the world's most famous spy, was captured by a group of drug dealers. He was sent to a small piece of land at the center of a lake filled with crocodiles. There he performed the most daring action to escape -- he jumped onto the head of the nearest crocodile! Before the animal realized what was happening, James jumped again onto the next big head... Finally he reached the bank before the last crocodile could bite him (actually the stunt man was caught by the big mouth and barely escaped with his extra thick boot).

Assume that the lake is a 100 by 100 square one. Assume that the center of the lake is at (0,0) and the northeast corner at (50,50). The central island is a disk centered at (0,0) with the diameter of 15. A number of crocodiles are in the lake at various positions. Given the coordinates of each crocodile and the distance that James could jump, you must tell him whether or not he can escape.

Input Specification:

Each input file contains one test case. Each case starts with a line containing two positive integers N (≤100), the number of crocodiles, and D, the maximum distance that James could jump. Then N lines follow, each containing the (x,y) location of a crocodile. Note that no two crocodiles are staying at the same position.

Output Specification:

For each test case, print in a line "Yes" if James can escape, or "No" if not.

Sample Input 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

Sample Output 1:

Yes

Sample Input 2:

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

Sample Output 2:

No

简单翻译:

就是在以所给的最远跳跃距离为半径这个限制,看能不能找到一条从湖心到湖岸的路径

主要思路:

(1)建图:建图的标准是能不能在两个节点之间跳跃,而判断能不能在两个节点之间跳跃的关键是将节点分为三类:岸,鳄鱼,岛

①:从岸边开始跳:注意岸是有半径的

②:最后跳上岸:注意只要x轴方向或者y轴方向有一个超过了边界就上岸了

③:在鳄鱼节点之间跳

实现上述判断的关键在于下面这个函数,其中都是考虑距离的平方:

bool CanJump(int jumpDistance, const Node* node1, const Node* node2) {  //判断能不能跳出分三种情况:从岛上开始跳,在两个鳄鱼之间跳,最后跳上岸
    bool flag = FALSE;
    double distanceSquareBetweenTwoNodes = DistanceSquare(node1, node2);
    if(node1->Xlabel == 0 && node1->Ylabel == 0 || node2->Xlabel == 0 && node2->Ylabel == 0) {  //注意,小岛是有半径的,判断如果其中有一个节点是岛
        if(distanceSquareBetweenTwoNodes <= pow(RADIUS + jumpDistance, 2)) {
            flag = TRUE;
        }
    }
    else if(node1->Xlabel == BOUNDRY && node2->Ylabel == BOUNDRY || node2->Xlabel == BOUNDRY && node2->Ylabel == BOUNDRY) { //传进来的节点之一是岸
        int x1 = node1->Xlabel;
        int x2 = node2->Xlabel;
        int y1 = node1->Ylabel;
        int y2 = node2->Ylabel;
        if(abs(x1 - x2) <= jumpDistance || abs(y1 - y2) <= jumpDistance) {
            flag = TRUE;
        }
    }
    else if(distanceSquareBetweenTwoNodes <= pow(jumpDistance, 2)) {    //如果两个节点都是鳄鱼节点
        flag = TRUE;
    }
    return flag;
}

 (二):搜索:

因为只要找到一条路径即可,而一定是从岛开始找,我选择了BFS(其实DFS也可以),用BFS搜索时,如果弹出的是岸就可以退出循环打印Yes,如果循环结束也没有找到打印No

第一次写错误:

相比之下,BFS到没那么难实现,真正难的倒是判断能不能在两个节点之间跳跃,一开始没注意岛的半径,然后又没有考虑跳上岸的条件

代码实现:

/*构造图,WEIGHT的标准是看能不能跳到*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX_NODE_NUMS 105
#define RADIUS 7.5
#define BOUNDRY 50
#define TRUE 1
#define FALSE 0
#define NONE -1
typedef int bool;
/*构造图*/
/*图的数据结构*/
typedef struct MatrixGraphNode MatrixGraphNode;
typedef MatrixGraphNode* MatrixGraph;
struct MatrixGraphNode {
    int NodeNums, EdgeNums;
    int Weight[MAX_NODE_NUMS][MAX_NODE_NUMS];
};
typedef struct Node Node;
struct Node {
    double Xlabel, Ylabel;
};
MatrixGraph CreateEmptyGraph (int nodeNums) {
    MatrixGraph graph = (MatrixGraph)malloc(sizeof(MatrixGraphNode));
    graph->NodeNums = nodeNums;
    for(int i = 0; i < nodeNums; i++) {
        for(int j = 0; j < nodeNums; j++) {
            graph->Weight[i][j] = FALSE;
        }
    }
    return graph;
}
void InsertEdge(int start, int end, MatrixGraph graph) {
    graph->Weight[start][end] = TRUE;
    graph->Weight[end][start] = TRUE;
    return;
}
double DistanceSquare(const Node* node1, const Node* node2) {
    double xLabel1 = node1->Xlabel;
    double yLabel1 = node1->Ylabel;
    double xLabel2 = node2->Xlabel;
    double yLabel2 = node2->Ylabel;
    double xDifference = xLabel1 - xLabel2;
    double yDifference = yLabel1 - yLabel2;
    return pow(xDifference, 2) + pow(yDifference, 2);
}
/*
如果有鳄鱼在小岛上
如果有鳄鱼在岸上
*/
bool CanJump(int jumpDistance, const Node* node1, const Node* node2) {  //判断能不能跳出分三种情况:从岛上开始跳,在两个鳄鱼之间跳,最后跳上岸
    bool flag = FALSE;
    double distanceSquareBetweenTwoNodes = DistanceSquare(node1, node2);
    if(node1->Xlabel == 0 && node1->Ylabel == 0 || node2->Xlabel == 0 && node2->Ylabel == 0) {  //注意,小岛是有半径的,判断如果其中有一个节点是岛
        if(distanceSquareBetweenTwoNodes <= pow(RADIUS + jumpDistance, 2)) {
            flag = TRUE;
        }
    }
    else if(node1->Xlabel == BOUNDRY && node2->Ylabel == BOUNDRY || node2->Xlabel == BOUNDRY && node2->Ylabel == BOUNDRY) { //传进来的节点之一是岸
        int x1 = node1->Xlabel;
        int x2 = node2->Xlabel;
        int y1 = node1->Ylabel;
        int y2 = node2->Ylabel;
        if(abs(x1 - x2) <= jumpDistance || abs(y1 - y2) <= jumpDistance) {
            flag = TRUE;
        }
    }
    else if(distanceSquareBetweenTwoNodes <= pow(jumpDistance, 2)) {    //如果两个节点都是鳄鱼节点
        flag = TRUE;
    }
    return flag;
}
MatrixGraph BuildGraph(int nodeNums, int jumpDistance) {
    int crocodileNums = nodeNums - 2;
    MatrixGraph graph = CreateEmptyGraph(nodeNums);
    Node allNode[nodeNums];
    allNode[0].Xlabel = 0;
    allNode[0].Ylabel = 0;
    allNode[nodeNums - 1].Xlabel = BOUNDRY;
    allNode[nodeNums - 1].Ylabel = BOUNDRY;
    for(int i = 1; i <= crocodileNums; i++) {
        scanf("%lf %lf", &allNode[i].Xlabel, &allNode[i].Ylabel);
    }
    for(int i = 0; i < nodeNums; i++) {
        for(int j = i; j < nodeNums; j++) {
            if(CanJump(jumpDistance, &allNode[i], &allNode[j])) {
                InsertEdge(i, j, graph);
            }
        }
    }
    return graph;
}
/*构造队列的数据结构*/
typedef struct QueueNode QueueNode;
typedef QueueNode* Queue;
struct QueueNode {
    int Data[MAX_NODE_NUMS];
    int Head, Rear, Size;
};
void InitQueue(Queue* q) {
    (*q)->Head = 0;
    (*q)->Rear = -1;
    for(int i = 0; i < MAX_NODE_NUMS; i++) {
        (*q)->Data[i] = NONE;
    }
}
bool IsFull(Queue* q) {
    if((*q)->Size == MAX_NODE_NUMS) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}
bool IsEmpty(Queue* q) {
    if((*q)->Size == 0) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}
int Dequeue(Queue* q) {
    if(IsEmpty(q)) {
        return NONE;
    }
    else {
        int ret = (*q)->Data[(*q)->Head++ % MAX_NODE_NUMS];
        (*q)->Size--;
        (*q)->Data[(*q)->Head - 1] = NONE;
        return ret;
    }
}
void Enqueue(Queue* q, int data) {
    if(!IsFull(q)) {
        (*q)->Data[++(*q)->Rear % MAX_NODE_NUMS] = data;
        (*q)->Size++;
        return;
    }
}
/*BFS*/
bool Vis[MAX_NODE_NUMS];
bool BFS(MatrixGraph graph, int index, int nodeNums) {
    Queue q = (Queue)malloc(sizeof(QueueNode));
    InitQueue(&q);
    Enqueue(&q, index);
    while(!IsEmpty(&q)) {
        int root = Dequeue(&q);
        if(root == NONE) {
            break;
        }
        if(root == nodeNums - 1) {
            return TRUE;
        }
        Vis[root] = TRUE;
        for(int i = 0; i < nodeNums; i++) {
            if(Vis[i] == FALSE && graph->Weight[root][i] == TRUE) {
                Vis[i] = TRUE;
                Enqueue(&q, i);
            }
        }
    }
    return FALSE;
}
/*判断能不能救出007*/
void Save007(MatrixGraph graph, int nodeNums) {
    if(BFS(graph, 0, nodeNums)) {
        printf("Yes");
    }
    else {
        printf("No");
    }
}
int main() {
    int crocodileNums, jumpDistance;
    scanf("%d %d", &crocodileNums, &jumpDistance);
    int nodeNums = crocodileNums + 2;   //总结点数量加2是因为还要考虑岛节点和边节点
    MatrixGraph graph = BuildGraph(nodeNums, jumpDistance);
    Save007(graph, nodeNums);
    free(graph);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值