• HDU1102 最小生成树prim算法


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102

    题意:给出任意两个城市之间建一条路的时间,给出哪些城市之间已经建好,问最少还要多少时间使所有的城市连通?

    思路:已经建好的城市之间需要的时间设为0,就是求最小生成树的权值和了。

    顺便复习一下prim算法。

    讲道理,好像我的prim算法没有判断加入这个点是不是会产生回路?

    回答:只有生成树集合里的点加入超过1次的时候,它还是要和集合里的某个点连一条边,于是就产生回路了。所以代码通过vis数组判断当前点是不是在生成树集合里

    就可以判断是不是会产生回路了。

    邻接表形式?

    知道思想就可以实现,才是合格的搬砖工,希望以后脱离模板。

    附代码:

    /*
    prim 最小生成树算法
    过程:prim算法将图分为两部分,假设原顶点集为V,将其分为S和V-S两部分,S为已经确定在最小生成树上的顶点,
    开始时,将任意一个顶点加入到S,然后每次在V-S中寻找距离S中的点最近的点。作为下一个加入最小生成树上的点。
    所有N个节点都加入到最小生成树中时,最小生成树构造完毕。
    
    实现:对于邻接矩阵构造的图,可以用low[N]保存每个顶点到已加入生成树中所有点的最小距离。
    每次寻找这个距离最小的一个点加入最小生成树中。再根据这个点的距离更新其它未加入生成树中的点。
    直到所有的点都加入到最小生成树中。
    */
    
    // Eg:HDU 1102
    
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #define inf 1000000
    using namespace std;
    
    int g[210][210];
    int low[210];
    int vis[210]; // 表示该点是否已经加入最小生成树中
    int n;
    
    int prim() {
        for (int i=0; i<n; ++i) {
            low[i] = g[0][i];
        }
    
        int ans = 0;
        memset(vis, 0, sizeof(vis));
        vis[0] = 1;
    
        for (int i=1; i<n; ++i) { // 循环n-1次,找剩下的n-1个点。
            int k = -1, mindis = inf;
            for (int j=0; j<n; ++j) { // 循环找当前剩下的点中 距离最小生成树点集距离最短的点。
                if (!vis[j] && low[j] < mindis) {
                    mindis = low[j];
                    k = j;
                }
            }
    
             if (k == -1) return -1;
             vis[k] = 1; // 加入最小生成树点集
             ans += mindis;
    
             for (int j=0; j<n; ++j) { // 更新没加入最小生成树的点中 距离是否会缩短。
                /*if (!vis[j] && low[j] > low[k] + g[k][j]) {
                        low[j] = low[k] + g[k][j];
                }*/
    
                 if (!vis[j] && low[j] > g[k][j]) { // 上面的if是错的。low数组存储的距离是当前点到生成树中所有点距离最小的的点。
                        low[j] = g[k][j]; // 因为这个点加入最小生成树集合中,可以和其中任意一个点连一条边。
                }
            }
        }
        return ans;
    }
    
    
    int main() {
        int q;
        while(cin >> n) {
            for (int i=0; i<n; ++i) {
                for (int j=0; j<n; ++j) {
                    cin >> g[i][j];
                }
            }
    
            cin >> q;
            for (int i=0; i<q; ++i) {
                int a, b;
                cin >> a >> b;
                a--, b--;
                g[a][b] = 0;
                g[b][a] = 0;
            }
    
            int ans = prim();
            cout << ans << endl;
        }
        return 0;
    }
    

      

  • 相关阅读:
    循环结构
    位运算符
    Switch 选择结构
    if结构和逻辑运算符
    变量和运算符
    [luogu1090 SCOI2003] 字符串折叠(区间DP+hash)
    [luogu2329 SCOI2005] 栅栏(二分+搜索)
    [luogu 4886] 快递员
    [luogu4290 HAOI2008]玩具取名(DP)
    [luogu2624 HNOI2008]明明的烦恼 (prufer+高精)
  • 原文地址:https://www.cnblogs.com/icode-girl/p/5294747.html
Copyright © 2020-2023  润新知