07-图5 Saving James Bond - Hard Version

news2024/11/17 17:27:29

题目:

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 a shortest path to reach one of the banks. The length of a path is the number of jumps that James has to make.

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, if James can escape, output in one line the minimum number of jumps he must make. Then starting from the next line, output the position (x,y) of each crocodile on the path, each pair in one line, from the island to the bank. If it is impossible for James to escape that way, simply give him 0 as the number of jumps. If there are many shortest paths, just output the one with the minimum first jump, which is guaranteed to be unique.

Sample Input 1:
17 15
10 -21
10 21
-40 10
30 -50
20 40
35 10
0 -10
-25 22
40 -40
-30 30
-10 22
0 11
25 21
25 10
10 10
10 35
-30 10
Sample Output 1:
4
0 11
10 21
10 35
Sample Input 2:
4 13
-12 12
12 12
-12 -12
12 -12
Sample Output 2:
0

手绘示意图:
基本逻辑和easy版本的一样。
在这里插入图片描述

算法逻辑与分析:
1.根据输入构造图
1.1顶点和边的表达
1.1.1顶点包括鳄鱼,湖心岛中心和湖岸;注:需要去除在岛上,岸边的鳄鱼。
为何要对顶点和邻接表排序?
根据题目输出要求:优选有最小第一条的路径。
If there are many shortest paths, just output the one with the minimum first jump,
which is guaranteed to be unique.
对顶点按从近到远排序和对邻接表按从近到远排序,保证优先处理“最小第一跳”。

1.1.2对于顶点和邻接表用typedef结构数组的方式表示,而不用结构数组指针,更方便调试。
1.1.3边是动态生成的,所以没有必要用Edge结构表达和传递
1.1.4边是跳跃距离D,根据跳跃距离,连接顶点,构造图

2.对图求最短路径
典型的无权单源最短路径算法,一点改动是需要对当前的顶点做判断,是否已经是出口

3.输出最小路径
自定义堆栈输出

代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>

#define MaxVertexNum 101 // 最多100条鳄鱼加上湖心岛
#define DistToBank 50
#define IslandRadius 7.5
#define NoExit -1

typedef int Vertex;

// 队列
typedef struct _Queue *Queue;
struct _Queue
{
    Vertex *Data;
    int front;
    int rear;
};

// 鳄鱼坐标(Coordinate Of Crocodile)
typedef struct _Coordinate
{
    int x, y;
} Coordinate[MaxVertexNum];

// 邻接点
typedef struct _AdjNode *AdjNode;
struct _AdjNode
{
    Vertex AdjV;
    AdjNode Next;
};

// 邻接表
typedef struct _AdjTable
{
    AdjNode FirstEdge;
} AdjTable[MaxVertexNum];

// 领接表表示的图
typedef struct _LGraph *LGraph;
struct _LGraph
{
    int Nv, Ne, Weight;    // 因为每跳是固定的值,所以Weight放在这里处理更简单
    Coordinate Crocodiles; // 鳄鱼坐标结构数组
    AdjTable Graph;        // 图
};

Queue createQ(int Nv);
void addQ(Queue Q, Vertex V);
Vertex delQ(Queue Q);
bool isEmpty(Queue Q);

LGraph createGraph(Coordinate Crocodiles, int Nv, int Weight);
bool isOnIsland(int x, int y);
bool isOnBank(int x, int y);
void sortVertexFromNearToFar(Coordinate Crocodiles, int Nv);
void sortAdjTableFromSmallToLarge(AdjNode FirstEdge);
bool isEdge(LGraph G, Vertex V, Vertex W);
void insertEdge(LGraph G, Vertex V, Vertex W);
bool isExit(LGraph G, Vertex V);
LGraph buildGraph();
Vertex BFS(LGraph G, Vertex S, int dist[], int path[]);
void save007(LGraph G);
void showPath(LGraph G, Vertex ExitID, int dist[], int path[]);
void freeGraph(LGraph G);

/*
输入1:
17 15
10 -21
10 21
-40 10
30 -50
20 40
35 10
0 -10
-25 22
40 -40
-30 30
-10 22
0 11
25 21
25 10
10 10
10 35
-30 10

输出1:
4
0 11
10 21
10 35

输入2:
4 13
-12 12
12 12
-12 -12
12 -12

输出2:
0
 */

int main()
{
    LGraph G = buildGraph();
    save007(G);
    freeGraph(G);

    return 0;
}

// 队列相关操作集
Queue createQ(int Nv)
{
    Queue Q = (Queue)malloc(sizeof(struct _Queue));
    Q->Data = malloc(Nv * sizeof(int));
    Q->front = Q->rear = -1;
    return Q;
}

void addQ(Queue Q, Vertex V)
{
    Q->rear++;
    Q->Data[Q->rear] = V;
}

Vertex delQ(Queue Q)
{
    Q->front++;

    return Q->Data[Q->front];
}

bool isEmpty(Queue Q)
{
    return Q->front == Q->rear ? true : false;
}

// 建图
LGraph buildGraph()
{ // N鳄鱼数量(顶点数),D跳跃距离(边的权重),(x,y)鳄鱼坐标,CrocodilesInLake有效的鳄鱼数
    int N, D, x, y, CrocodilesInLake = 0;
    scanf("%d %d", &N, &D);
    // 读入鳄鱼坐标
    Coordinate Crocodiles;

    for (int i = 0; i < N; i++)
    {
        scanf("%d %d", &x, &y);
        // 剔除不在湖里的鳄鱼
        if (!isOnIsland(x, y) && !isOnBank(x, y))
        {
            Crocodiles[CrocodilesInLake].x = x;
            Crocodiles[CrocodilesInLake].y = y;
            CrocodilesInLake++;
        }
    }

    // 将顶点从近到远排序
    sortVertexFromNearToFar(Crocodiles, CrocodilesInLake);

    // 建立只含顶点的初始图
    LGraph G = createGraph(Crocodiles, CrocodilesInLake, D);

    // 插入边
    Vertex V, W;
    for (V = 0; V < G->Nv - 1; V++)
    {
        for (W = V + 1; W < G->Nv; W++)
        {
            if (isEdge(G, V, W))
            { // 因为V,W不是固定的,而Weight又是固定的,所以没有必要先构造Edge,再插入
                insertEdge(G, V, W);
            }
        }
    }

    // 邻接表排序
    for (V = 0; V < G->Nv; V++)
    {
        sortAdjTableFromSmallToLarge(G->Graph[V].FirstEdge);
    }
    // 完成图的创建
    return G;
}

// 在岛上的鳄鱼
bool isOnIsland(int x, int y)
{
    float dist = sqrt(pow(x, 2) + pow(y, 2));

    if (dist <= IslandRadius)
    {
        return true;
    }
    else
    {
        return false;
    }
}

// 在岸上的鳄鱼
bool isOnBank(int x, int y)
{
    if (abs(x) >= DistToBank || abs(y) >= DistToBank)
    {
        return true;
    }
    else
    {
        return false;
    }
}

// 将顶点从近到远排序[选择排序]
void sortVertexFromNearToFar(Coordinate Crocodiles, int Nv)
{
    int i, j, min;
    // Coordinate Temp;
    struct _Coordinate Temp;
    for (i = 0; i < Nv - 1; i++)
    {
        min = i;
        for (j = i + 1; j < Nv; j++)
        {
            if (pow(Crocodiles[min].x, 2) + pow(Crocodiles[min].y, 2) >
                pow(Crocodiles[j].x, 2) + pow(Crocodiles[j].y, 2))
            {
                min = j;
            }
        }
        if (min != i)
        {
            Temp = Crocodiles[i];
            Crocodiles[i] = Crocodiles[min];
            Crocodiles[min] = Temp;
        }
    }
}

// 建立只含顶点的初始图
LGraph createGraph(Coordinate Crocodiles, int Nv, int Weight)
{
    LGraph G = (LGraph)malloc(sizeof(struct _LGraph));
    G->Nv = Nv + 1; // 将小岛也作为一个顶点归入图中,所以+1;
    G->Ne = 0;
    G->Weight = Weight;
    G->Crocodiles[0].x = G->Crocodiles[0].y = 0; // 小岛坐标

    Vertex V;
    for (V = 1; V < G->Nv; V++)
    {
        G->Crocodiles[V] = Crocodiles[V - 1]; // 读入顶点
    }

    for (V = 0; V < G->Nv; V++)
    {
        G->Graph[V].FirstEdge = NULL;
    }

    return G;
}

// 判断两个顶点是否有边
bool isEdge(LGraph G, Vertex V, Vertex W)
{
    bool ret = false;
    float dist = sqrt(pow(G->Crocodiles[W].x - G->Crocodiles[V].x, 2) +
                      pow(G->Crocodiles[W].y - G->Crocodiles[V].y, 2));
    if (V == 0)
    { // 小岛要单独考虑
        if (dist - IslandRadius <= G->Weight)
        {
            ret = true;
        }
    }
    else
    {
        if (dist <= G->Weight)
        {
            ret = true;
        }
    }

    return ret;
}

// 将边插入图中
void insertEdge(LGraph G, Vertex V, Vertex W)
{
    AdjNode newNode;

    newNode = (AdjNode)malloc(sizeof(struct _AdjNode));
    newNode->AdjV = W;
    newNode->Next = G->Graph[V].FirstEdge;
    G->Graph[V].FirstEdge = newNode;
    // 用邻接表表示无权图,1条边要插入2次
    newNode = (AdjNode)malloc(sizeof(struct _AdjNode));
    newNode->AdjV = V;
    newNode->Next = G->Graph[W].FirstEdge;
    G->Graph[W].FirstEdge = newNode;

    G->Ne++;
}

void sortAdjTableFromSmallToLarge(AdjNode FirstEdge)
{
    Vertex Temp;
    AdjNode p, q;

    for (p = FirstEdge; p; p = p->Next)
    {
        for (q = p->Next; q; q = q->Next)
        {
            if (q->AdjV < p->AdjV)
            {
                Temp = q->AdjV;
                q->AdjV = p->AdjV;
                p->AdjV = Temp;
            }
        }
    }
}

// 判断是否是出口
bool isExit(LGraph G, Vertex V)
{
    bool ret = false;

    if (V == 0)
    { // 能否从岛上跳到岸边?
        if ((DistToBank - IslandRadius) <= G->Weight)
        {
            ret = true;
        }
    }
    else if (DistToBank - abs(G->Crocodiles[V].x) <= G->Weight ||
             DistToBank - abs(G->Crocodiles[V].y) <= G->Weight)
    {
        ret = true;
    }

    return ret;
}

Vertex BFS(LGraph G, Vertex S, int dist[], int path[])
{
    Vertex V, ExitID = NoExit;
    AdjNode W;
    dist[S] = 0;
    Queue Q = createQ(G->Nv);
    addQ(Q, S);
    while (!isEmpty(Q))
    {
        V = delQ(Q);
        // 由于是递增的遍历,所以第一个找到的出口一定是首跳最短路径出口,可以break出来
        if (isExit(G, V))
        {
            ExitID = V;
            break;
        }

        for (W = G->Graph[V].FirstEdge; W; W = W->Next)
        {
            if (dist[W->AdjV] == -1)
            {
                dist[W->AdjV] = dist[V] + 1;
                path[W->AdjV] = V;
                addQ(Q, W->AdjV);
            }
        }
    }

    free(Q->Data);
    free(Q);

    return ExitID;
}

// 拯救007
void save007(LGraph G)
{
    int dist[G->Nv], path[G->Nv];
    Vertex V;
    for (V = 0; V < G->Nv; V++)
    {
        dist[V] = path[V] = -1;
    }
    // BFS遍历寻找出口,并带出出口值
    Vertex ExitID = BFS(G, 0, dist, path);

    // 按题目要求输出
    if (ExitID == NoExit)
    {
        printf("0\n");
    }
    else
    {
        showPath(G, ExitID, dist, path);
    }
}

// 利用堆栈输出具体路径
void showPath(LGraph G, Vertex ExitID, int dist[], int path[])
{
    int minJumps = dist[ExitID] + 1; // 要加上最后从出口鳄鱼跳上岸的那一步
    printf("%d\n", minJumps);

    Vertex Stack[G->Nv];
    int Top = -1;

    while (ExitID != -1)
    {
        Top++;
        Stack[Top] = ExitID;
        ExitID = path[ExitID];
    }
    Top--; // 最上面存的是小岛的坐标,不需要输出
    while (Top != -1)
    {
        printf("%d %d\n", G->Crocodiles[Stack[Top]].x, G->Crocodiles[Stack[Top]].y);
        Top--;
    }
}

void freeGraph(LGraph G)
{
    AdjNode p, q;
    Vertex V;

    for (V = 0; V < G->Nv; V++)
    {
        for (p = G->Graph[V].FirstEdge; p; p = q)
        {
            q = p->Next;
            free(p);
        }
    }
    // G->Crocodiles和G->Graph不是通过malloc分配的空间,所以无需用free释放
    //  free(G->Crocodiles);
    //  free(G->Graph);
    free(G);
}

测试结果:
在这里插入图片描述
小结:
非常精彩的一道题,是无权图单源最短路的一个典型应用,需要对该算法有有深刻的认识,并灵活应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/705671.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

golang cannot find package xxx in any of

目录结构如下 报错 cannot find package xxx in any of 1是路径没配对&#xff0c;把src去掉&#xff0c;因为GOPATH的规则好像是自动识别目录下的src路径&#xff0c;所以改成下面即可 2是别勾这个 否则会如下报错 含义参考 Enable Go modules integration在做什么 - 知乎 gol…

video-08-videojs黑屏问题(详解总结)

博主在开发的时候遇到这种情况&#xff0c;video黑屏问题&#xff0c;问题有两种情况&#xff0c;一种是视频黑屏且不可以播放&#xff0c;另一种是视频黑屏且自己播放&#xff0c;事件可以监听到 目录 一、问题类型1 视频黑屏且不可以播放 1.1 原因 1.2 解决方案思路 1.3 代…

fast admin报错:Unexpected token ‘<‘, “ (已解决)

报错信息&#xff1a; 在新加视图的时候的&#xff0c;点击编辑/添加忽然报这个错误&#xff0c;网上找了半天&#xff0c;js、视图、修修改改最后竟是一个小问题&#xff1b; 解决方法&#xff1a; 改为&#xff1a; 简单的说就是&#xff1a;btn-ajax ->btn-dialog

C# 二叉树的后序遍历

145 二叉树的后序遍历 给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[3,2,1] 示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[] 示例 3&#xff1a; 输入…

php未定义索引数组怎么解决

在PHP中&#xff0c;如果使用一个未定义的数组索引&#xff0c;就会出现未定义索引错误。在这种情况下&#xff0c;需要采取措施解决这个问题。本文将为您介绍几种解决php未定义索引数组的方法。 1.使用isset()函数检查数组索引是否存在 使用函数isset()可以检查一个变量是否…

A股股民调查:58%股民表示“亏惨了”

A股上半年赚钱效应究竟如何&#xff1f; 东方财富网的一份调查显示&#xff0c;有58%的股民表示今年上半年亏惨了&#xff0c;另有9%的股民略有浮亏。 成交“先冷后热”、基金发行遇冷 A股的上半年已正式收官&#xff01;A股三大指数上半年涨跌不一&#xff0c;其中沪指累涨…

希尔排序(C语言)

希尔排序 一、希尔排序的原理二、动图演示三、代码实现四、实现从小到大排序五、希尔排序的优缺点 一、希尔排序的原理 希尔排序是插入排序的一种更高效的改进版本。 1.将原始待排数据按照设定的增量gap分成多组&#xff0c;每组有n / gap个元素。 2.对这些分组进行插入排序&a…

Linux 学习记录43(C++篇)

Linux 学习记录43(C篇) 本文目录 Linux 学习记录43(C篇)一、友元1. 友元函数(1. 全局函数作为友元函数(2. 类中的成员函数作为友元 2. 友元类3. 友元的注意事项 二、常成员函数和常对象(const)1.常成员函数2. 常对象3. mutable 关键字 三、运算符重载1. 常见的运算符2. 运算符重…

【海思SS528 | MPP】音频例程 sample_audio.c 源码阅读笔记

目录 一、概述二、main 函数解析三、main_inner 函数解析四、sample_audio_ai_ao 函数解析4.1 Audio Codec相关配置 五 一、概述 上篇文章 【海思SS528】MPP媒体处理软件V5.0 | 音频模块 - 学习笔记 学习了海思MPP媒体处理平台的一小部分音频知识&#xff0c;这篇文章继续学习与…

(5)深度学习学习笔记-多层感知机

文章目录 多层感知机和激活函数代码来源 多层感知机和激活函数 通过在网络中加入一个或多个隐藏层来克服线性模型的限制&#xff0c;使其能处理更普遍的函数关系类型。最简单的方法是将多个全连接层堆叠在一起。每一层都输出到上面的层&#xff0c;直到生成最后的输出&#xf…

Android12之ServiceManager::addService添加服务的本质(一百五十八)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

Python-创建虚拟环境并指定环境目录

1.简介 程序运行依赖于环境&#xff0c;不同程序依赖的环境不尽相同。如果一个项目依赖于一个第三方库的1.0版本&#xff0c;另一个项目依赖于这个第三方库的2.0版本&#xff0c;在一个python环境中一个库只能同时存在一个版本&#xff0c;所以就产生了版本冲突。虚拟环境就是为…

git 显示不出图标

今天写完代码准备上传 gitee 的时候发现&#xff0c;自己的本地文件夹没有小绿勾了&#xff0c;整的我一时分不清到底哪些文件已经上传过。 研究了半天终于搞定了&#xff0c;现在把方法记录下来&#xff0c;防止以后继续出现这种问题还要找半天。 1. 打开注册表 win R 打开运…

【Python 随练】按键变色

题目&#xff1a; Press any key to change color, do you want to try it. Please hurry up! 简介&#xff1a; 在本篇博客中&#xff0c;我们将解决一个编程问题&#xff1a;按下任意键改变颜色。我们将提供一个完整的代码示例来实现这个功能&#xff0c;并鼓励读者尝试。…

亚马逊云科技自研芯片,为企业云服务提高性价比

6月27日至28日&#xff0c;2023亚马逊云科技中国峰会于上海顺利召开。在本次峰会上&#xff0c;似乎找寻到了云计算领域竞争对手均日渐成熟&#xff0c;而亚马逊云科技却能一直保持领先地位的原因——过去的十几年里&#xff0c;亚马逊云科技“基于客户需求&#xff0c;快速进行…

gnutls_handshake() failed: The TLS connection was non-properly terminated.

从远程仓库获取所有更新&#xff0c;并保存在本地时&#xff0c;使用git fetch 命令时出现如下错误&#xff1a; 解决办法&#xff1a; 问题解决&#xff1a; 参考资料 拉取github报错 gnutls_handshake() failed: The TLS connection was non-properly terminated. git获取…

proteus三级管(NPN)仿真LED灯串的开关

实验里设置LED灯的导通电压为1.2V 打开仿真开关后可以看到&#xff0c;此时三极管不导通&#xff0c;LED灯亮了&#xff0c;并且电压表和电流探针有数值显示 按下按键&#xff0c;三级管导通&#xff0c;LED灯灭

Spring MVC相关注解运用 —— 上篇

目录 一、Controller、RequestMapping 1.1 示例程序 1.2 测试结果 二、RequestParam 2.1 示例程序 2.2 测试结果 三、RequestHeader、CookieValue 3.1 示例程序 3.2 测试结果 四、SessionAttributes 4.1 示例程序 4.2 测试结果 五、ModelAttribute 5.1 示例程序 …

4G/wifi/lora投入式无线液位传感变送器 mqtt/http协议对接云平台

1.产品概述 DAQ-GP-TLL4G无线液位传感器终端是上海数采物联网科技有限公司推出的一款无线液体水位测量产品。原理是利用扩散硅片上的一个惠斯通电桥&#xff0c;被测介质&#xff08;气体或液体&#xff09;施压使桥壁电阻值发生变化&#xff08;压阻效应&#xff09;&#xff…

A_B_C滑块

分享一个有意思的滑块。 网址:https://xxgs.chinanpo.mca.gov.cn/gsxt/newList 图片好看,不知道说啥了,验证部分。 ok,源码在这,自提。 # -*- coding:utf-8 -*- # author: qinshaowen # V:15702312233 import requests,base64 import execjs,ddddocr from loguru impo…