• 某车企笔试题解答(2)


    目录

    承接前面的问题,附加题:

    答:

    1修改对DAG进行拓扑排序的函数

    2 求解

    以下是代码清单:

    运行结果:

    3 时间复杂度分析


    承接前面的问题,附加题:

    如果棋盘非常大(0

    答:

    本问题虽然沿用前一个问题的数学模型DAG,但是应充分利用只有很少的格子上有豆子的条件,在计算中尽量排除那些没有豆子的格子,才能降低时间复杂度。

    将棋盘上有豆子的格点两两连起来,忽略没有豆子的格点,组成一个有向无环图(DAG)。连接任意两点之间的边的指向同样要保证是从左向右,从上到下。无法满足此要求的两点不连接。由于每个格子只有一个豆子,所以这个DAG的每条边的权重都是相等的,不妨设为1。要让吃豆人吃到最多的豆子,就变成了搜索此DAG的最长路径的问题。

    解答分为3部分:一、修改对DAG进行拓扑排序的函数,在保证排序正确性的基础上降低其复杂度;二、求解;三、时间复杂度分析。

    1修改对DAG进行拓扑排序的函数

    在拓扑排序中,从顶点u到顶点v的每个有向边uv,u在排序中都在v之前。这里我们重写上题解答中的拓扑排序函数topologicalSortUtil()。新函数不再对棋盘上每一个格子进行排序,而是只对含有豆子的格子进行拓扑排序。

    排序步骤如下:

    1) 找到一个含有豆子的格子u,其坐标为(x,y),同时建立一个变量,记录以u为起点的边数。

    2) 找到另外一个有豆子的格子v,其坐标为(s,t)。

    3) 假如s>=x 且 t>=y,则u可以到达v,于是以u为起点的边数加1,并在两者之间建立一条边,从u指向v;否则则不加1。

    4) 重复2)和3)的操作,遍历所有的k-1个格子,算出以u为起点的边总数。

    5) 重复1)2)3)4)的操作,遍历所有的k个格子,算出每个有豆子的格子的边数。

    6) 准备一个stack,存放拓扑排序后的顶点集合。

    7) 找到所有的以其自身为起点的边总数为0的格子,将它们放入stack。既然不存在以它们为起点的边,那么这些格子之间不会有边连接。根据拓扑排序的性质,“从顶点u到顶点v的每个有向边uv,u在排序中都在v之前”,这些格子不论在stack中彼此次序如何,都不会违背这个性质。

    8) 找到所有的以其自身为起点的边总数为1的格子,将它们放入stack。这些格子彼此之间不会相互连接。(假如这些格子彼此之间存在边连接,那么作为这条边起点的格子的边总数将至少等于2—这条边的终点的格子算一个,而既然这条边的终点的格子的边总数为1,以其为起点的边指向的格子又算一个—也就破坏了“边总数为1的”的假设。)由于相互不连接,它们相互的次序不会破坏拓扑排序的性质。

    9) 找到所有的以其自身为起点的边总数为p(p=2,3,4,….)的格子,将它们放入stack。这些格子彼此之间不会相互连接。由于相互不连接,它们相互的次序不会破坏拓扑排序的性质。

    10) 重复第9步,直到所有的含有豆子的格子全被录入stack。

    11) 将格子(0,0)作为最顶层的元素放入stack。拓扑排序完成。

    2 求解

    1) 输入变量是一个vector,vector由所有含有豆子的格子组成。每个格子用一个二元结构体表示。结构体的两个分量分别表示格子的横坐标和纵坐标。

    2) 按照前面的步骤对这个vector进行拓扑排序。排序的同时也生成了相应的DAG。

    3) 调用前一个问题中的函数Graph::longestPath(int s)返回最长路径。

    以下是代码清单:

    1. // A C++ program to find single source longest distances
    2. // in a DAG
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #define NINF INT_MIN
    10. using namespace std;
    11. struct ST_POS
    12. {
    13.     int     x;
    14.     int     y;
    15. };
    16. // Graph is represented using adjacency list. Every
    17. // node of adjacency list contains vertex number of
    18. // the vertex to which edge connects. It also
    19. // contains weight of the edge
    20. class AdjListNode {
    21.     int v;
    22.     int weight;
    23. public:
    24.     AdjListNode(int _v, int _w)
    25.     {
    26.         v = _v;
    27.         weight = _w;
    28.     }
    29.     int getV() { return v; }
    30.     int getWeight() { return weight; }
    31. };
    32. // Class to represent a graph using adjacency list
    33. // representation
    34. class Graph {
    35.     int V; // No. of vertices'
    36.     // Pointer to an array containing adjacency lists
    37.     list* adj;
    38.     list<int>        *   pPath;
    39.     unique_ptr<int[]>    m_upCount;
    40. public:
    41.     Graph(int V); // Constructor
    42.     ~Graph(); // Destructor
    43.     // function to add an edge to graph
    44.     void addEdge(int u, int v, int weight);
    45.     // Finds longest distances from given source vertex
    46.     void longestPath(int s, stack<int>);
    47.     // A function used by longestPath
    48.     stack<int> topologicalSortUtil(vector);
    49. };
    50. Graph::Graph(int V) // Constructor
    51. {
    52.     this->V = V;
    53.     adj = new list[V];
    54.     pPath = new list<int>[V];
    55.     m_upCount.reset(new int[V]);
    56. }
    57. Graph::~Graph() // Destructor
    58. {
    59.     delete[] adj;
    60.     delete[] pPath;
    61. }
    62. void Graph::addEdge(int u, int v, int weight)
    63. {
    64.     AdjListNode node(v, weight);
    65.     adj[u].push_back(node); // Add v to u's list
    66. }
    67. //排序,并产生DAG
    68. stack<int> Graph::topologicalSortUtil(vector vecPos)
    69. {
    70.     int iLen = vecPos.size();
    71.     for (int k = 0; k < iLen; k++)
    72.     {
    73.         //找到一个含有豆子的格子u,其坐标为(x,y),同时建立一个变量,记录以u为起点的边数
    74.         int iCount = 0;
    75.         ST_POS u = vecPos.at(k);
    76.         for (int l = 0; l < iLen; l++)
    77.         {
    78.              if (l != k)
    79.              {
    80.                  ST_POS v = vecPos.at(l);
    81.                  //找到另外一个有豆子的格子v,其坐标为(s,t)
    82.                  if (v.x >= u.x && v.y >= u.y)
    83.                  {
    84.                      //假如s>=x 且 t>=y,则u可以到达v,于是以u为起点的边数加1,并在两者之间建立一条边,从u指向v;否则则不加1
    85.                      iCount++;
    86.                      addEdge(k, l, 1);//由于每个格子只有一个豆子,所以这个DAG的每条边的权重都是相等的,不妨设为1。
    87.                  }
    88.              }
    89.         }
    90.         m_upCount[k] = iCount;
    91.     }
    92.     //找到所有的以其自身为起点的、边总数为p(p=0,1,2,3,4,….)的格子,将它们放入stack,并且放在边总数为p-1的格子之前
    93.     stack<int> Stack;
    94.     int iLevel = 0;
    95.     while (Stack.size() < iLen)
    96.     {
    97.         for (int k = 0; k < iLen; k++)
    98.         {
    99.              if (m_upCount[k] == iLevel)
    100.                  Stack.push(k);
    101.         }
    102.         iLevel++;
    103.     }
    104.    
    105.     return Stack;
    106. }
    107. // The function to find longest distances from a given vertex.
    108. void Graph::longestPath(int s, stack<int> Stack)
    109. {
    110.     int * dist = new int[V];
    111.     // Initialize distances to all vertices as infinite and
    112.     // distance to source as 0
    113.     for (int i = 0; i < V; i++)
    114.     {
    115.         pPath[s].clear();
    116.         dist[i] = NINF;
    117.     }
    118.        
    119.     dist[s] = 0;
    120.     pPath[s].push_back(s);
    121.     // Process vertices in topological order
    122.     while (Stack.empty() == false) {
    123.         // Get the next vertex from topological order
    124.         int u = Stack.top();
    125.         Stack.pop();
    126.         // Update distances of all adjacent vertices
    127.         list::iterator i;
    128.         if (dist[u] != NINF) {
    129.              for (i = adj[u].begin(); i != adj[u].end(); ++i)
    130.              {
    131.                  if (dist[i->getV()] < dist[u] + i->getWeight())
    132.                  {
    133.                      //更新与u相连的各个顶点到s的距离
    134.                      dist[i->getV()] = dist[u] + i->getWeight();
    135.                      //更新具体路径
    136.                      pPath[i->getV()].assign(pPath[u].begin(), pPath[u].end());
    137.                      pPath[i->getV()].push_back(i->getV());
    138.                  }  
    139.              }
    140.         }
    141.     }
    142.     // Print the calculated longest distances
    143.     for (int i = 0; i < V; i++)
    144.     {
    145.         cout << "length:                                      -----------";
    146.         (dist[i] == NINF) ? cout << "unReachable" : cout << dist[i];
    147.         cout<< endl;
    148.         cout << "path: ";
    149.         for (const auto & item : pPath[i])
    150.         {
    151.              cout << item << " ";
    152.         }
    153.         cout << endl;
    154.     }
    155.        
    156.     delete [] dist;
    157. }
    158. // Driver program to test above functions
    159. int main()
    160. {
    161.     vector vecNodes = { { 0, 0 }, { 0, 3 }, { 1, 2 }, { 1, 4 }, { 1, 5 }, { 1, 6 },
    162.     { 2, 0 }, { 2, 1 }, { 2, 4 }, { 3, 3 }, { 3, 4 }, { 4, 4 }, { 5, 0 }, { 5, 2 }, { 5, 3 },
    163.     { 6, 1 }, { 6, 3 }, { 6, 5 } };
    164.     Graph g(vecNodes.size());
    165.     stack<int> Stack = g.topologicalSortUtil(vecNodes);
    166.     int s = 0;
    167.     cout << "Following are longest distances from "
    168.         "source vertex "
    169.         << s << " \n";
    170.     g.longestPath(s, Stack);
    171.     cin.get();
    172.     return 0;
    173. }

    运行结果:

    最大路径长度是6,途径格子0-6-7-9-14-16-17

    棋盘上豆子分布如图,数字是每个格子的编号:

    3 时间复杂度分析

    整个程序分为两部分:拓扑排序函数topologicalSortUtil和计算最长路径函数longestPath

    1. 在拓扑排序的过程中遍历了所有的含有豆子的格子(k个),并且对每个格子,又遍历了其他含有豆子的格子(k-1个)。因此拓扑排序的过程的时间复杂度为O(k2)。
    2. longestPath函数遍历了DAG的所有顶点,也就是所有的含有豆子的格子,共k个。对于每个顶点,又更新了与之相连的所有其他顶点到(0,0)的距离,这些顶点的个数不超过k-1。所以longestPath函数带来的时间复杂度不超过O(k^2)。

    综合1与2,整个程序的时间复杂度为O(k2" role="presentation">k2)

  • 相关阅读:
    类之间的关系
    前端开发,自定义本地域名解析,更改host,模拟线上环境
    训练日志捏
    【JavaSE】数据类型与变量
    最新 umi4-max 如何使用 webpack5 联邦模块
    Echarts画散点图
    网络编程
    springboot+vue练手级项目,真实的在线博客系统
    疫情之下,我帮你总结了全网最全的Java面试高频考点
    c++ 类的特殊成员函数:移动构造函数(五)
  • 原文地址:https://blog.csdn.net/liji_digital/article/details/127845525