九度 1347:孤岛连通工程(最小生成树)

总结

1. Objects in a set are immutable; if you want to modify an object, you need to:

a. make a copy of the object from the set

b. modify the copy

c. remove the original object from the object, and

d. insert the copy into the set

 

2. Each associative container is parameterized on Key and an ordering relation Compare that induces a strict weak ordering on elements of Key

 

3. Two key k1 and k2 are cosideraed to be equivalent if for the comparision object comp, comp(k1, k2) == false && comp(k2, k1) == false

 

strict weak order 要求让比较函数对相等的值返回 false

 

4. 这道题使用 STL SET 实属画蛇添足, 因为 SET 自定义类型的比较函数难以定义. 在下面的代码中, SET 仅将 i==j==cost 的点视为相同 

 

题目描述:

现在有孤岛n个,孤岛从1开始标序一直到n,有道路m条(道路是双向的,如果有多条道路连通岛屿i,j则选择最短的那条),请你求出能够让所有孤岛都连通的最小道路总长度。

 

思路

1. 求解最小耗费树

2. 最小耗费树的算法有 Prim算法和 Kruskal 算法, 两者皆为贪心算法

Prim 算法扩展当前树, Kruskal 每次加入耗费最小的安全边

3. Prim 算法需要 priority_queue, Kruskal 算法需要使用并查集, 一般来说还是 Kruskal 算法易于实现

 

代码 使用了 STL SET 导致超时, 不过案例均 AC

#include <iostream>
#include <stdio.h>
#include <set>
#include <memory.h>
using namespace std;

int n, m;
int father[10100];

class Edge {
public:
    int i, j, cost;

    Edge(int _i, int _j, int _cost):i(_i), j(_j), cost(_cost) {}
    Edge() {
        Edge(0, 0, 0);
    }
    bool operator<(const Edge &ths) const {
        if(this->cost == ths.cost) {
            if(this->i == ths.i) {
                return this->j < ths.j;
            }
            return this->i < ths.i;
        }
        return this->cost < ths.cost;
    }
};

int myFind(int x) {
    if(x == father[x])
        return x;
    else {
        father[x] = myFind(father[x]);
    }
    return father[x];
}

bool merge(int a, int b) {
    int fa = myFind(a);
    int fb = myFind(b);

    if(fa == fb)
        return false;

    father[fa] = fb;
    return true;
}

int main() {
    freopen("testcase.txt", "r", stdin);
    while(scanf("%d%d", &n, &m) != EOF) {
        set<Edge> edges;
        for(int i = 1; i <= n; i ++)
            father[i] = i;

        
        for(int k = 0; k < m; k ++) {
            int i, j, cost;
            scanf("%d%d%d", &i, &j, &cost);
            Edge newEdge(i, j, cost);

            if(edges.count(newEdge)) {
                int oldcost = edges.find(newEdge)->cost;
                edges.erase(edges.find(newEdge));
                newEdge.cost = min(oldcost, newEdge.cost);
            }

            edges.insert(newEdge);
            
        }

        set<Edge>::iterator it_set;
        int res = 0;
        for(it_set = edges.begin(); it_set != edges.end(); it_set ++) {
            int i = it_set->i;
            int j = it_set->j;
            int cost = it_set->cost;

            if(merge(i, j)) {
                res += cost;
            }
        }

        int visited = 0;
        for(int i = 1; i <= n; i ++) {
            if(i == father[i])
                visited ++;
        }

        if(visited == 1)
            cout << res << endl;
        else
            cout << "no" << endl;
    }
    return 0;
}

 

 

 

posted @ 2014-03-10 16:37  SangS  阅读(326)  评论(0编辑  收藏  举报