数据结构PTA 进阶实验6-3.4 拯救007(升级版)

进阶实验6-3.4 拯救007(升级版)

题目

在老电影“007之生死关头”(Live and Let Die)中有一个情节,007被毒贩抓到一个鳄鱼池中心的小岛上,他用了一种极为大胆的方法逃脱 —— 直接踩着池子里一系列鳄鱼的大脑袋跳上岸去!(据说当年替身演员被最后一条鳄鱼咬住了脚,幸好穿的是特别加厚的靴子才逃过一劫。)

设鳄鱼池是长宽为100米的方形,中心坐标为 (0, 0),且东北角坐标为 (50, 50)。池心岛是以 (0, 0) 为圆心、直径15米的圆。给定池中分布的鳄鱼的坐标、以及007一次能跳跃的最大距离,你需要给他指一条最短的逃生路径 —— 所谓“最短”是指007要跳跃的步数最少。

输入格式:
首先第一行给出两个正整数:鳄鱼数量 N(≤100)和007一次能跳跃的最大距离 D。随后 N 行,每行给出一条鳄鱼的 (x,y) 坐标。注意:不会有两条鳄鱼待在同一个点上。

输出格式:
如果007有可能逃脱,首先在第一行输出007需要跳跃的最少步数,然后从第二行起,每行给出从池心岛到岸边每一步要跳到的鳄鱼的坐标 (x,y)。如果没可能逃脱,就在第一行输出 0 作为跳跃步数。如果最短路径不唯一,则输出第一跳最近的那个解,题目保证这样的解是唯一的。

输入样例 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

解法

思路
这道题目与常规的图的题目有一个很大的区别,就是它没有直接地告诉你哪些边是存在的,这是需要用距离计算公式来判断的,如果两点之间的距离在可跳范围内,那么它这条边就是实际存在的。

因此解决此题需要进行以下步骤:

  1. 创建一个图,此图类型为:

typedef struct GNode *PtrToGNode;
typedef PtrToGNode MGraph;
struct GNode
{
int Nv;
WeightType G[MAXN][MAXN];
DataType D[MAXN];
};

其中DataType应该是一个结构体,存储顶点的横纵坐标

  1. 在创建图的操作中,需要做读图操作,将所给的数据全部读入在图Graph中。其次,还可以把判断边的步骤放在这里,两个for循环嵌套,判断哪些点是相邻的(即可跳的)。
  2. 用Floyd算法计算所有点之间的最短路径。
  3. 用一个SearchFirstJump函数来寻找,所有顶点中,从0,0点能跳到的点。把这些点用一个数组存储起来。
  4. 用一个SearchEndJump函数来寻找,所有顶点中,能跳上岸的点。把这些点用一个数组存储起来。
  5. 在步骤4和步骤5的两个数组中,各取一个元素FirstPoint和EndPoint,然后在Floyd算法中得到的Dist数组中能是Dist取最小值的FirstPoint和EndPoint。如果Dist相同,则比较FirstPoint离原点的远近。
  6. 用PrintResult迭代输出顶点坐标

实现

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


#define MAXN 100+1
#define INFINITY 10000

int JumpDist = 0;

typedef int Vertex;
typedef int WeightType;
typedef struct DataT DataType;
struct DataT
{
    int X;
    int Y;
};

typedef struct GNode *PtrToGNode;
typedef PtrToGNode MGraph;
struct GNode
{
    int Nv;
    WeightType G[MAXN][MAXN];
    DataType D[MAXN];
};

typedef struct TestNode *TestFE;
struct TestNode
{
    int Num;
    Vertex Arr[MAXN];
};

MGraph CreateGraph(int VertexNum)
{
    MGraph Graph = (MGraph)malloc(sizeof(struct GNode));
    Graph->Nv = VertexNum;

    Vertex i,j;
    for(i=0; i<Graph->Nv; i++)
        for(j=0; j<Graph->Nv; j++)
            Graph->G[i][j] = INFINITY;

    return Graph;
}

int IsEdge(DataType P1, DataType P2)
{
    int deltaX = P1.X - P2.X;
    int deltaY = P1.Y - P2.Y;

    if(deltaX*deltaX + deltaY*deltaY <= JumpDist*JumpDist)
        return 1;
    else
        return 0;
}

MGraph BuildGraph(int VertexNum)
{
    MGraph Graph = CreateGraph(VertexNum);
//    Graph->Date[0].X = 0;
//    Graph->Data[0].Y = 0;

    Vertex i,j;
    for(i=0; i<Graph->Nv; i++)
        scanf("%d %d", &Graph->D[i].X, &Graph->D[i].Y);

    for(i=0; i<Graph->Nv; i++)
    {
        Graph->G[i][i] = 0;

        for(j=i+1; j<Graph->Nv; j++)
        {
            if(IsEdge(Graph->D[i], Graph->D[j]))
            {
                Graph->G[i][j] = 1;
                Graph->G[j][i] = 1;
            }
        }
    }

    return Graph;
}

void Floyd(MGraph Graph, int Path[][MAXN], int Dist[][MAXN])
{
    Vertex i,j,k;
    for(i=0; i<Graph->Nv; i++)
    {
        for(j=0; j<Graph->Nv; j++)
        {
            Dist[i][j] = Graph->G[i][j];
            Path[i][j] = -1;
        }
    }

    for(k=0; k<Graph->Nv; k++)
        for(i=0; i<Graph->Nv; i++)
            for(j=0; j<Graph->Nv; j++)
    {
        if(Dist[i][k] + Dist[k][j] < Dist[i][j])
        {
            Dist[i][j] = Dist[i][k] + Dist[k][j];
            Path[i][j] = k;
        }
    }

}

TestFE SearchFirstJump(MGraph Graph)
{
    TestFE FirstJump = (TestFE)malloc(sizeof(struct TestNode));
    FirstJump->Num = 0;

    Vertex i;
    int deltaX, deltaY;
    for(i=0; i<Graph->Nv; i++)
    {
        deltaX = Graph->D[i].X;
        deltaY = Graph->D[i].Y;
        if(deltaX*deltaX + deltaY*deltaY < (JumpDist+7.5)*(JumpDist+7.5))
        {
            FirstJump->Arr[FirstJump->Num++] = i;
        }
    }

    return FirstJump;
}

TestFE SearchEndJump(MGraph Graph)
{
    TestFE EndJump = (TestFE)malloc(sizeof(struct TestNode));
    EndJump->Num = 0;

    Vertex i;
    int deltaX, deltaY;
    for(i=0; i<Graph->Nv; i++)
    {
        deltaX = Graph->D[i].X;
        deltaY = Graph->D[i].Y;
        if( Graph->D[i].X+JumpDist>=50 || Graph->D[i].X-JumpDist<=-50 || Graph->D[i].Y+JumpDist>=50 || Graph->D[i].Y-JumpDist<=-50)
        {
            EndJump->Arr[EndJump->Num++] = i;
        }
    }

    return EndJump;
}

int IsClose(MGraph Graph, Vertex V1, Vertex V2)
{
    if(pow(Graph->D[V1].X, 2) + pow(Graph->D[V1].Y, 2) < pow(Graph->D[V2].X, 2) + pow(Graph->D[V2].Y, 2))
        return 1;
    else
        return 0;
}

void PrintResult(MGraph Graph, int Path[][MAXN], Vertex Start, Vertex End)
{
    int k = Path[Start][End];
    if(k == -1)
    {
        printf("%d %d\n", Graph->D[Start].X, Graph->D[Start].Y);

    }
    else
    {
        PrintResult(Graph, Path, Start, k);
        PrintResult(Graph, Path, k, End);
    }
    //printf("%d %d\n", Graph->D[End].X, Graph->D[End].Y);
}

int main()
{

    int N;
    scanf("%d %d", &N, &JumpDist);
    //N = N+1;
    if(JumpDist >= 50-7.5)
    {
        printf("1\n");
    }
    else
    {
        MGraph Graph = BuildGraph(N);
        int Path[MAXN][MAXN];
        int Dist[MAXN][MAXN];

        Floyd(Graph, Path, Dist);
        TestFE FirstJump = SearchFirstJump(Graph);
        TestFE EndJump = SearchEndJump(Graph);

        WeightType MinJumNum = INFINITY;
        Vertex MinStart, MinEnd;
        MinStart = 0;

        int i,j, FirstPoint, EndPoint;

        for(i=0; i<FirstJump->Num; i++)
        {
            FirstPoint = FirstJump->Arr[i];
            for(j=0; j<EndJump->Num; j++)
            {
                EndPoint = EndJump->Arr[j];
                if(Dist[FirstPoint][EndPoint] < MinJumNum)
                {
                    MinJumNum = Dist[FirstPoint][EndPoint];
                    MinStart = FirstPoint;
                    MinEnd = EndPoint;
                }
                else if(Dist[FirstPoint][EndPoint] == MinJumNum && IsClose(Graph, FirstPoint, MinStart))
                {
                    MinStart = FirstPoint;
                    MinEnd = EndPoint;
                }
            }
        }
        if(MinJumNum == INFINITY)
        {
            printf("0");
        }
        else
        {
            printf("%d\n", MinJumNum+2);
            PrintResult(Graph, Path, MinStart, MinEnd);
            printf("%d %d\n", Graph->D[MinEnd].X, Graph->D[MinEnd].Y);
        }

    }



    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值