UVA1151 最小生成树
2017年7月19日题目的大意是平面上有 n 个点,让你将这 n 个点连接起来,连接任意两个点间的费用为两点间欧几里得距离的平方.同时有 q 个套餐,买第 qi 个套餐花费 ci .买了某个套餐后,套餐中所有点都已经连接.求将所有点连起来的最小花费.
做法是用二进制的思想来枚举购买哪些套餐,将套餐中的点加入到并查集中.然后求最小生成树就好了.
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n, q;
struct point {
int x, y;
} p[N];
struct edge {
int from, to, cost;
bool operator < (const edge & a) const {
return cost < a.cost;
}
} e[N * N];
int f[N * N];
int root(int x)
{
return x == f[x] ? x : f[x] = root(f[x]);
}
vector<int> vip[10];
int vipcost[10];
int main()
{
int tt;
scanf("%d", &tt);
bool flag = false;
while (tt--) {
if (flag)
putchar('\n');
if (!flag)
flag = true;
scanf("%d %d", &n, &q);
for (int i = 0; i < q; i++) {
vip[i].clear();
int a;
scanf("%d %d", &a, &vipcost[i]);
while (a--) {
int x;
scanf("%d", &x);
vip[i].push_back(x);
}
}
for (int i = 0; i < n; i++) {
scanf("%d %d", &p[i].x, &p[i].y);
}
int cnt = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int cost = (p[i].x - p[j].x) * (p[i].x - p[j].x) + (p[i].y - p[j].y) * (p[i].y - p[j].y);
e[cnt].from = i + 1;
e[cnt].to = j + 1;
e[cnt].cost = cost;
cnt++;
}
}
sort(e, e + cnt);
int ans = (int) 1e9;
for (int s = 0; s < 1 << q; s++) {
int cost = 0;
for (int i = 1; i <= cnt; i++) {
f[i] = i;
}
for (int i = 0; i < q; i++) {
if (s & 1 << i) {
cost += vipcost[i];
for (int k = 0; k < (int) vip[i].size() - 1; k++) {
f[root(vip[i][k])] = root(vip[i][k + 1]);
}
}
}
for (int i = 0; i < cnt; i++) {
if (root(e[i].from) == root(e[i].to))
continue;
f[root(e[i].from)] = root(e[i].to);
cost += e[i].cost;
}
ans = min(ans, cost);
}
cout << ans << endl;
}
return 0;
}