• 中国大学MOOC-数据结构基础习题集、06-3、公路村村通


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

    题目分析:典型最小生成树问题,且只需输出树各边的权值之和出来就可以了。博主这里用的是Prim算法。

    特别说明:

      1. 用邻接矩阵表示图比较容易。保存路径长度就可以了。因为强调了数组下标从1开始,因此在输入完n和m时,先执行一步n++,方便以后为数组申请空间。

      2. 二维数组的动态申请及初始化,不推荐大家#define一个较大的数,然后直接int a[MAX][MAX],这样做是十分不负责的,十分浪费空间。如果不会的同学,可以参见如下方法:

     1     // 用邻接矩阵存储图
     2     int **data = new int*[n];
     3     for(int i=0; i<n+1; i++)
     4     {
     5         data[i] = new int[n];
     6     }
     7     // 邻接矩阵初始化
     8     for(int i=0; i<n; i++)
     9     {
    10         for(int j=0; j<n; j++)
    11         {
    12             data[i][j] = MAXNUM;
    13         }
    14     }

      3. 求“尚未收集”的dist值最小的函数,参数是dist,collected标记是否被收集,及数组的长度n。注意数组下标从1开始:

     1 int minDist(int dist[], bool collected[], int n)
     2 {
     3     int mindist = MAXNUM;
     4     int icount = NOTEXIST;
     5     for(int i=1; i<n ; i++)
     6     {
     7         if(dist[i] < mindist && collected[i] == false)
     8         {
     9             icount = i;
    10             mindist = dist[i];
    11         }
    12     }
    13     return icount;
    14 }

      4. 用#define定义无穷大(100000000)和不存在(-1),避免程序中出现魔数,也方便修改。

    1 #define MAXNUM 10000000
    2 #define NOTEXIST -1

      5. 可以用fill函数,对一个数组进行快速初始化,避免写for循环。方法如下:

    1 fill(a, a+aLen, 100);    // 数组a长度为aLen,用100填满整个数组

    代码分析:

      普利姆算法:24~71(其中parent数组不设定也可以,这里并没有要求表示树的结构)

      主函数:72~100(注意输入图的数据时,注意是图是无向图,也就是双向图)

      1 #include <iostream>
      2 #include <stack>
      3 
      4 #define MAXNUM 10000000
      5 #define NOTEXIST -1
      6 
      7 using namespace std;
      8 
      9 int minDist(int dist[], bool collected[], int n)
     10 {
     11     int mindist = MAXNUM;
     12     int icount = NOTEXIST;
     13     for(int i=1; i<n ; i++)
     14     {
     15         if(dist[i] < mindist && collected[i] == false)
     16         {
     17             icount = i;
     18             mindist = dist[i];
     19         }
     20     }
     21     return icount;
     22 }
     23 
     24 int Prim(int *data[], int n, int m)
     25 {
     26     // 集合: 用来存储收集到的结点
     27     stack<int> MST;
     28     MST.push(0);
     29     // dist: 记录长度
     30     int *dist = new int[n];
     31     fill(dist, dist+n, MAXNUM);
     32     dist[1] = 0;
     33     // collected: 标记是否被访问
     34     bool *collected = new bool[n];
     35     fill(collected, collected+n, false);
     36     // parent: 记录树的结构
     37     int *parent = new int[n];
     38     fill(parent, parent+n, NOTEXIST);
     39     // output: 最终结果
     40     int output = 0;
     41     while (1)
     42     {
     43         int V = minDist(dist, collected, n);
     44         if (V == NOTEXIST)
     45             break;
     46         MST.push(V);
     47         output += dist[V];
     48         dist[V] = 0;
     49         collected[V] = true;
     50         for(int W=1; W<n; W++)
     51         {
     52             if(data[V][W] != MAXNUM         // 如果W是V的邻接点
     53                && collected[W] == false     // 如果W没有被访问
     54                && data[V][W] < dist[W])
     55             {
     56                 dist[W] = data[V][W];
     57                 parent[W] = V;
     58             }
     59         }
     60     }
     61     if(MST.size() != n)
     62         return NOTEXIST;
     63     else
     64         return output;
     65 }
     66 /*
     67 dist[V] = E(s,V)或 正无穷
     68 parent[s] = -1(代表根结点)
     69 T = O( |V|2 )
     70 */
     71 
     72 int main()
     73 {
     74     int n, m;
     75     cin >> n >> m;
     76     n++;
     77     // 用邻接矩阵存储图
     78     int **data = new int*[n];
     79     for(int i=0; i<n+1; i++)
     80     {
     81         data[i] = new int[n];
     82     }
     83     // 邻接矩阵初始化
     84     for(int i=0; i<n; i++)
     85     {
     86         for(int j=0; j<n; j++)
     87         {
     88             data[i][j] = MAXNUM;
     89         }
     90     }
     91     for(int i=0; i<m; i++)
     92     {
     93         int a, b, c;
     94         cin >> a >> b >> c;
     95         data[a][b] = c;
     96         data[b][a] = c;
     97     }
     98     cout << Prim(data, n, m) << endl;
     99     return 0;
    100 }

    AC成果:

  • 相关阅读:
    你真的了解wordwrap和wordbreak的区别吗?
    python入门3——基本数据类型 岳岳
    python入门04——输入输出 岳岳
    第一次计算机理论知识 岳岳
    Web 开发与设计之 Google 兵器谱
    Web 开发与设计之 Google 兵器谱
    Web 开发与设计之 Google 兵器谱
    window.showModalDialog 以及window.open用法简介
    Web 开发与设计之 Google 兵器谱
    Web 开发与设计之 Google 兵器谱
  • 原文地址:https://www.cnblogs.com/clevercong/p/4215966.html
Copyright © 2020-2023  润新知