zoukankan      html  css  js  c++  java
  • PTA 08-图7 公路村村通 (30分)

    现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

    输入格式:

    输入数据包括城镇数目正整数NN(le 10001000)和候选道路数目MM(le 3N3N);随后的MM行对应MM条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到NN编号。

    输出格式:

    输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出-11,表示需要建设更多公路。

    输入样例:

    6 15
    1 2 5
    1 3 3
    1 4 7
    1 5 4
    1 6 2
    2 3 4
    2 4 6
    2 5 2
    2 6 6
    3 4 6
    3 5 1
    3 6 1
    4 5 10
    4 6 8
    5 6 3
    

    输出样例:

    12

    /*
     * 这题边数e <= 3*顶点数  不是稀疏图  故以邻接矩阵进行存储 采用prim算法。 (下面也写了个kruskal加最小堆的实现)
     * findMin()函数找最小值可以用最小堆进行优化。(这里不用最小堆优化用了24ms~~ 用最小堆和kruskal写12ms- -!)
    */
    #include "iostream"
    using namespace std;
    #define INF  999999
    int map[1005][1005];
    int n, m; 
    int lowCost[1005];
    long ans = 0;
    int findMin() {
        int minCost = INF;
        int k, j;
        for (k = 0, j = 1; j <= n; j++) {
            if (lowCost[j] && lowCost[j] < minCost) {
                minCost = lowCost[j];
                k = j;
            }
        }
        return k;
    }
    int prim() {
        for (int i = 1; i <= n; i++) {
            lowCost[i] = map[1][i];
        }
        lowCost[1] = 0; /* 从序号为1的顶点出发生成最小生成树 */
        for (int i = 1; i < n; i++) { /* 生成树还需要收n-1个节点 */
            int  k = findMin(); /* 找到到生成树距离最短的节点 */
            if (k) {
                ans += lowCost[k];
                lowCost[k] = 0;
                for (int j = 2; j <= n; j++) { /* 更新当前的最小生成树 */
                    if (lowCost[j] && map[k][j] < lowCost[j]) {
                        lowCost[j] = map[k][j];
                    }
                }
            }
            else {
                return -1;
            }
        }
        return ans;
    }
    void init() {
        cin >> n >> m;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++) {
                if (i == j) {
                    map[i][j] = 0;
                }
                else {
                    map[i][j] = INF;
                }
            }
        while (m--) {
            int c1, c2, c3;
            cin >> c1 >> c2 >> c3;
            map[c1][c2] = map[c2][c1] = c3;
        }
    }
    int main() {
        init();
        cout<<prim()<<endl;
    }
    /*
     * kruskal加最小堆的实现(可能是数据量比较小吧~ 这个稠密图用krukal加了个最小堆跑的比前面的prim快了一倍)
    */
    #include "iostream"
    using namespace std;
    #define INF  0
    struct Node {
        int s, e;
        int cost;
    }edge[3001];
    int father[1001];
    int Size = 0;  
    int v, e;
    void makeHeap() {  /* 将数组调整成小顶堆 O(e)的时间复杂度 */
        int child, parent;
        Size = e;
        edge[0].cost = INF; /* 哨兵 */
        int i = Size / 2;
        for (; i >= 1; i--) {
            Node temp = edge[i]; 
            for (parent = i; parent * 2 <= Size; parent = child)
            {
                child = parent * 2; /* 先指向左孩子 */
                if ((child != Size) && edge[child].cost > edge[child + 1].cost) { /* 右孩子*/
                    child++;
                }
                if (temp.cost <= edge[child].cost) {
                    break;
                }
                else
                    edge[parent] = edge[child];
            }
            edge[parent] = temp;
        }
    }
    Node deleteMinFromHeap() { /* 从小顶堆中删除元素  在调整成小顶堆  时间复杂度O(log e)*/
        Node temp = edge[Size--]; 
        Node minItem = edge[1];
        //cout << Size << endl;
        int parent, child;
        for ( parent = 1; parent * 2 <= Size; parent = child) {
            child = parent * 2;
            if ((child != Size) && (edge[child].cost > edge[child+1].cost)) {
                child += 1; /* 找左右孩子中较小者 */
            }
            if (temp.cost <= edge[child].cost) break;
            else edge[parent] = edge[child];
        }
        edge[parent] = temp;
        return minItem;
    }
    void init() {
    //    cout << "v--->" << v << endl;
        for (int i = 1; i <= v; i++)
            father[i] = -1; /* 初始化为当前树的节点数的相反数 */
    }
    int find(int x) { /* 查询根节点  */
        if (father[x] <= -1)
            return x;
        else
            return father[x] = find(father[x]); /* 路径压缩  */
    }
    
    void Union(int x, int y) {
        x = find(x);
        y = find(y);
        if (father[x] < father[y]) {  /* 按节点数大小进行归并 */
            father[x] += father[y];
            father[y] = x;
        }
        else {
            father[y] += father[x];
            father[x] = y;
        }
    }
    int main() {
        int ans = 0;
        cin >> v >> e;
        for (int i = 1; i <= e; i++) {
            cin >> edge[i].s >> edge[i].e >> edge[i].cost;
        }
        makeHeap();
        init();
        int k = 1;
        for(int i = 1 ;i <= e; i++) {  
            Node node = deleteMinFromHeap();  /* 总的复杂度 O(e * log v) */
            int x = find(node.s); /*O(1)*/
            int y = find(node.e); 
            if (x != y) {
                ans += node.cost;
                Union(node.s, node.e); /*O(1)*/
                k++;
                if (k == v) {
                    break;
                }
            }
        }
        if (k != v)
            cout << -1 << endl;
        else
        cout << ans << endl;
        return 0;
    }
  • 相关阅读:
    Asp.Net中virtual、override理解
    SQL 知道字段名 全表搜索此字段属于哪个表
    C#中(int)a和Convert.ToInt32(a)的区别
    sql 查询表共多少列
    理解字节和字符
    C# IIS7.0+ Web.Config 配置Session过期时间
    Java版的扫雷游戏源码
    Activiti6.0教程 28张表解析 (三)
    Activiti6.0教程 Service用途剖析 (二)
    Activiti6.0教程 Eclipse安装Activiti Diagram插件(一)
  • 原文地址:https://www.cnblogs.com/minesweeper/p/6114804.html
Copyright © 2011-2022 走看看