zoukankan      html  css  js  c++  java
  • 中国大学MOOC-数据结构基础习题集、06-1、Saving James Bond

    题目链接:http://www.patest.cn/contests/mooc-ds/06-1

    题目分析:这是一道考察图的广度优先遍历,同时也要借助于Dijstra算法的一道题。题目的背景与上周的05-2是相同的:007被困在一个孤岛上,孤岛的直径是15,池塘的范围是[±50, ±50]。池塘中鳄鱼的条数及坐标,007的跳跃半径通过输入给出。问007能否借助于池塘中的鳄鱼逃出生天?和上周要求不同的是,需要把最短路径长度及最短路径输出,在有多条最短路径的情况下,输出第一跳最近的那条。

    特别说明:

      1. 是否建立图随意,用若干个数组表示也可以。博主最开始是没有建的,但是这次贴的代码是建好图的(邻接表)。一方面是为了练习自己的编码能力,一方面也是给对建图不熟悉的同学们举个“栗子”。感兴趣的同学可以关注下103~158行。

      2. 题目中要求“多条最短路径输出第一跳最近的那条”,博主查找了许多别的资料,最后使用的优先级队列。使用时需要重载小于运算符(即operator<)。将在孤岛上能踩到的所有鳄鱼结点,以距孤岛中心的距离为优先级,放入优先级队列中。然后依次取出,做广度优先遍历。这部分在165~180+行。

      3. 在做广度优先遍历时,如果已经可以逃脱,要确定当前是否为最短路径,是则记录路径。可以关注一下198~215行。

      4. 求两点间距离的函数,要判断其中一点是不是“岛屿”,如果是的话,结果要加上孤岛的半径。函数的定义在63~78行。

      5. 如果Case4过不去的朋友,请试一下我的用例1。如果是Case5过不去的朋友,请试一我的用例2。

    建议测试如下数据: 

      4 20 -27 0 -41 0 0 26 0 40

      博主这里输出结果是:3 0 26 0 40

      1 42.5

      博主这里输出结果是:1

    代码分析:

      注释写的非常详细,大家可以阅读一下:

      1 #include <iostream>
      2 #include <algorithm>
      3 #include <vector>
      4 #include <cmath>
      5 #include <queue>
      6 #include <stack>
      7 
      8 using namespace std;
      9 
     10 /*
     11  * 所用结构体的声明
     12  * pos 坐标结构体
     13  * vexNode 邻接表中的结点
     14  */
     15 struct pos;
     16 template <class T> struct vexNode;
     17 
     18 /*
     19  * 宏定义的声明
     20  * FIRSTSTEP 小岛的半径,固定为7.5
     21  * BORDER 边界的大小,固定为50
     22  * MAXNUM 无穷大
     23  */
     24 
     25 #define FIRSTSTEP 7.5
     26 #define BORDER 50
     27 #define MAXNUM 100000000
     28 
     29 /*
     30  * 全局变量的声明
     31  * vec 存储鳄鱼的坐标
     32  * eVec 邻接表存储图
     33  * pathVec 用来存储路径
     34  */
     35 
     36 vector<pos> vec;
     37 vector<vexNode<int> > eVec;
     38 vector<int> pathVec;
     39 
     40 struct pos
     41 {
     42     double x;
     43     double y;
     44     pos(double a, double b):x(a),y(b) {}
     45 };
     46 
     47 template <class T>
     48 struct vexNode
     49 {
     50     T data;
     51     vexNode<T> *next;
     52     vexNode(T d, vexNode<T> *n = NULL):data(d), next(n) {}
     53     bool friend operator<(const vexNode &a, const vexNode &b)
     54     {
     55         int V = a.data;
     56         int W = b.data;
     57         int dV = vec[V].x * vec[V].x + vec[V].y * vec[V].y;
     58         int dW = vec[W].x * vec[W].x + vec[W].y * vec[W].y;
     59         return dV < dW; // 出队先出大的,再出小的
     60     }
     61 };
     62 
     63 /*
     64  * 计算两点之间的距离
     65  */
     66 double Distance(pos p1, pos p2, int dis)
     67 {
     68     double xx = (p1.x - p2.x) * (p1.x - p2.x);
     69     double yy = (p1.y - p2.y) * (p1.y - p2.y);
     70     if((p1.x == 0 && p1.y == 0) || (p2.x == 0 && p2.y == 0))
     71     {
     72         return dis + FIRSTSTEP - sqrt(xx + yy);
     73     }
     74     else
     75     {
     76         return dis - sqrt(xx + yy);
     77     }
     78 }
     79 
     80 /*
     81  * 获得路径
     82  */
     83 vector<int> getPath(int t, int p[])
     84 {
     85     vector<int> path;
     86     for(; t!=-1; t=p[t])
     87         path.push_back(t);
     88     reverse(path.begin(),path.end());
     89     return path;
     90 }
     91 
     92 int main()
     93 {
     94     int nNum;
     95     double dis;
     96     cin >> nNum >> dis;
     97     // 考虑特殊情况,能否一步迈出
     98     if(dis + FIRSTSTEP >= BORDER)
     99     {
    100         cout << "1" << endl;
    101         return 0;
    102     }
    103     // 起始点(小岛)也算一个点
    104     vec.push_back(pos(0, 0));
    105     eVec.push_back(vexNode<int>(0));
    106     nNum ++;
    107     // 用邻接表存储图
    108     for(int i=1; i<nNum; i++)
    109     {
    110         double a, b;
    111         cin >> a >> b;
    112         vec.push_back(pos(a,b));
    113         eVec.push_back(vexNode<int>(i));
    114     }
    115     // 开始建图
    116     for(int i=0; i<nNum; i++)
    117     {
    118         for(int j=0; j<nNum; j++)
    119         {
    120             if(i != j)
    121             {
    122                 if(Distance(vec[i], vec[j], dis) >= 0)
    123                 {
    124                     // 查一查有没有重复的
    125                     bool myIFlag = false;
    126                     vexNode<int> *p = &eVec[i];
    127                     while(p -> next != NULL)
    128                     {
    129                         p = p -> next;
    130                         if(p -> data == j)
    131                         {
    132                             myIFlag = true;
    133                             break;
    134                         }
    135                     }
    136                     // 如果没有重复的,就插在最后边
    137                     if(myIFlag == false)
    138                         p -> next = new vexNode<int>(j);
    139 
    140                     // 因为是无向图,也就是双向图,所以另一侧也要插
    141                     bool myJFlag = false;
    142                     vexNode<int> *q = &eVec[j];
    143                     while(q -> next != NULL)
    144                     {
    145                         q = q -> next;
    146                         if(q -> data == i)
    147                         {
    148                             myJFlag = true;
    149                             break;
    150                         }
    151                     }
    152                     // 如果没有重复的,就插在最后边
    153                     if(myJFlag == false)
    154                         q -> next = new vexNode<int>(i);
    155                 }
    156             }
    157         }
    158     }
    159     // 相关数据结构的申请
    160     int *dist = new int[nNum];
    161     int *path = new int[nNum];
    162     priority_queue<vexNode<int> > myQueue;
    163 
    164     // 算法开始
    165     // 1. 在相同的最短路里找第一步最小的放入优先级队列中
    166 
    167     vexNode<int> *p = &eVec[0];
    168     while(p -> next != NULL)
    169     {
    170         p = p -> next;
    171         myQueue.push(eVec[p->data]);
    172         path[p->data] = 0;
    173     }
    174     int flag = 1;   // flag用来标记是否是第一次
    175     int minDist;    // minDist记录最小的dist值
    176 
    177     // 2. 从岛屿开始,能到达的所有结点做循环
    178 
    179     while(!myQueue.empty())
    180     {
    181         // 2.1 初始化
    182         for(int i=0; i<nNum; i++)
    183         {
    184             dist[i] = -1;
    185             path[i] = -1;
    186         }
    187         // 2.2 从队列中弹出一个结点,从这个结点开始,借助另一个队列,进行BFS
    188         vexNode<int> vN = myQueue.top();
    189         myQueue.pop();
    190         path[vN.data] = 0;      // 从myQueue队列中取出的结点,parent一定为岛屿(0,0)
    191         queue<int> bfsQueue;    // 进行BFS所需要的队列
    192         bfsQueue.push(vN.data);
    193         dist[vN.data] = 0;      // 初始的dist值为0
    194         while(!bfsQueue.empty())
    195         {
    196             int W = bfsQueue.front();
    197             bfsQueue.pop();
    198             // 2.3 判定是不是已经可以上岸了
    199             if(fabs(vec[W].x-BORDER)<=dis || fabs(vec[W].x+BORDER)<=dis
    200                     ||fabs(vec[W].y-BORDER)<=dis ||(vec[W].y+BORDER)<=dis)
    201             {
    202                 // 2.3.1 如果是第一次,更新minDist值,并记录路径
    203                 if(flag&&W!=0)
    204                 {
    205                     minDist = dist[W];
    206                     flag = 0;
    207                     pathVec = getPath(W, path);
    208                 }
    209                 // 2.3.2 如果不是第一次,则比较minDist值与dist值,并更新路径
    210                 else if(W!=0 && dist[W] <= minDist)
    211                 {
    212                     minDist = dist[W];
    213                     pathVec = getPath(W, path);
    214                 }
    215             }
    216             // 2.4 如果没有上岸,则将其邻接结点放入队列中,并更新dist与path的值
    217             else
    218             {
    219                 for(int i=1; i<=nNum; i++)
    220                 {
    221                     if(Distance(vec[W], vec[i], dis) >= 0 && dist[i] == -1)
    222                     {
    223                         bfsQueue.push(i);
    224                         dist[i]=dist[W]+1;
    225                         path[i]=W;
    226                     }
    227                 }
    228             }
    229 
    230         }
    231     }
    232 
    233     // 3. 输出最终结果
    234 
    235     if(pathVec.size() == 0)
    236         cout << "0" << endl;
    237     else
    238     {
    239         // 3.1 因为我们把(0,0)也当成结点了,这里不用+1
    240         cout << pathVec.size() << endl;
    241         for(int i=0; i<pathVec.size(); i++)
    242             // 3.2 因为我们把(0,0)也当成结点了,但是不能让它输出,所以特殊考虑
    243             if(vec[pathVec[i]].x == 0 and vec[pathVec[i]].y == 0)
    244                 ;
    245             else
    246                 cout << vec[pathVec[i]].x << " " << vec[pathVec[i]].y << endl;
    247     }
    248     return 0; 
    249 }

    AC成果:

  • 相关阅读:
    CSS定位 position
    时间日期类--显示时间
    【HDOJ】4775 Infinite Go
    【HDOJ】4297 One and One Story
    【HDOJ】4056 Draw a Mess
    【HDOJ】2242 考研路茫茫——空调教室
    【HDOJ】3828 A + B problem
    【HDOJ】3386 Final Kichiku “Lanlanshu”
    【HDOJ】1648 Keywords
    【HDOJ】1699 The comment in cpp
  • 原文地址:https://www.cnblogs.com/clevercong/p/4214292.html
Copyright © 2011-2022 走看看