poj1586 最小生成树

题目链接在这里

题目大意:

一个星球之间的居民想相互之间建立联系。建立联系需要每户购买设备,每个设备只能供和一位其他居民联系。居民和居民之间有距离,每个居民购买设备的价格也不一样。问如果让所有的居民之间相互建立联系,最少需要花费多少。

解题思路:

每个居民之间两两建边,边的权值是两者之间的距离加上每户人家购买设备的价格的总和。然后根据这些边建立最小生成树。

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define rep(i, x) for(int i = 0; i < x; ++i)
#define clr(x) memset(x, 0, sizeof(x))
using namespace std;
const int MaxN = 1005;

int t, n;
int map[MaxN][MaxN];
int money[MaxN];
int par[MaxN], r[MaxN];
struct Edge{
    int x, y, val;
    bool operator < (const Edge &e) const{
        return val > e.val;
    }
};

int Find(int x){
    if(x == par[x]) return x;
    return par[x] = Find(par[x]);
}

void unite(int x, int y){
    x = Find(x);
    y = Find(y);
    if(x == y)  return;
    if(r[x] < r[y]) par[x] = y;
    else{
        par[y] = x;
        if(r[x] == r[y])    ++r[x];
    }
}

bool check(int x, int y){
    return Find(x) == Find(y);
}


int main(){
    ios::sync_with_stdio(false);
    cin >> t;
    while(t--){
        priority_queue que;
        clr(r);
        rep(i, MaxN) par[i] = i;
        cin >> n;
        rep(i, n)   cin >> money[i];
        rep(i, n){
            rep(j, n){
                cin >> map[i][j];
            }
        }
        rep(i, n){
            rep(j, i){
                que.push(Edge{i, j, money[i] + money[j] + map[i][j]});
            }
        }

        int ans = 0;
        while(--n){
            Edge e = que.top();
            que.pop();
            if(check(e.x, e.y)){
                ++n;
                continue;
            }
            ans += e.val;
            unite(e.x, e.y);
        }
        cout << ans << endl;
    }
    return 0;
}

 

你可能感兴趣的:(最小生成树)