题目链接在这里
题目大意:
一个星球之间的居民想相互之间建立联系。建立联系需要每户购买设备,每个设备只能供和一位其他居民联系。居民和居民之间有距离,每个居民购买设备的价格也不一样。问如果让所有的居民之间相互建立联系,最少需要花费多少。
解题思路:
每个居民之间两两建边,边的权值是两者之间的距离加上每户人家购买设备的价格的总和。然后根据这些边建立最小生成树。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <queue>
#include <algorithm>
#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<Edge> 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;
}