zoukankan      html  css  js  c++  java
  • 畅通工程(最小生成树)

    题目描述

    省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
    Input
    测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
    行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
    Output
    对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
    Sample Input
    3 3
    1 2 1
    1 3 2
    2 3 4
    1 3
    2 3 2
    0 100
    Sample Output
    3
    ?

    题目分析

    问题是要建一个最短的公路,就是最小生成树问题。采用Kruskal算法求解。

    关于Kruskal的思想,就是先把所有边由小到大排序,然后每次选择最小的边加入树中,加入时做一个判断,是否两个顶点已经在树中(这里用到了并查集)。如果在树中,则不做操作,接着下一边,如果不在树中,那么就把两个顶点归到树中,然后加上边长。最后不断累加得到的边长就是最小距离。

    这里会有一个判定,因为不一定能有最小生成树出来。所以如果操作的边数没有等于顶点数-1。那么说明还有一些顶点没有进入最小生成树,输出?。

    代码

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    
    using namespace std;
    #define MAXM 105
    #define MAXN 105
    
    struct Edge {
        int u, v;
        int dist;
    };
    Edge edges[MAXM];
    
    int V, E; //顶点数,边数
    
    //并查集相关
    int par[MAXN]; //值为父亲的编号
    int rank1[MAXN]; //高度
    //初始化n个元素
    void init(int n) {
        for (int i = 1; i <= n; i++) {
            par[i] = i;
            rank1[i] = 0;
        }
    }
    //查询树的根
    int find(int x) {
        if (par[x] == x)
            return x;
        else
            return find(par[x]);
    }
    //合并x和y的集合
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        if (rank1[x] < rank1[y]) {
            par[x] = y;
        } else {
            par[y] = x;
            if (rank1[x] == rank1[y])
                rank1[x]++;
        }
    }
    //判断是否x,y是否是同一个集合
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    
    bool comp(const Edge& e1, const Edge& e2) {
        return e1.dist < e2.dist;
    }
    
    void kruskal() {
        init(V);
        sort(edges, edges + E, comp);
        
        int ans = 0;
        int count = 0;
        for (int i = 0; i < E; i++) {
            Edge e = edges[i];
            if (!same(e.u, e.v)) {
                unite(e.u, e.v);
                ans += e.dist;
                //printf("%d ", ans);
                count++;
                if (count == V - 1)
                    break;
            }
        }
        if (count < V - 1)
            printf("?
    ");
        else
            printf("%d
    ", ans);
    }
    int main() {
        while (scanf("%d%d", &E, &V) != EOF) {
            if (E == 0) break;
    
            for (int i = 0; i < E; i++) {
                scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].dist);
            }
            kruskal();
        }
        return 0;
    }
    
  • 相关阅读:
    [mock open]PyUnit执行单元测试时使用字符串模拟文件对象
    bottle 0.5中的key-value数据库
    bottle模板中的替换
    返回不同值的小技巧
    带有参数的装饰器
    常用命令速查
    SQLAlchemy多线程下事务隔离机制详解
    Bancor 协议浅析
    Flask中 endpoint 解析
    pip 相关问题
  • 原文地址:https://www.cnblogs.com/wudongwei/p/9370451.html
Copyright © 2011-2022 走看看