套餐只有8个,可以暴力枚举。不过边太多,不能枚举套餐都求一遍最小生成树。
其实只需要在一开始求出不包含套餐的最小生成树,把这些边记下来备用。之后枚举套餐的时候,先把套餐中的点全部加入并查集,然后在原最小生成树的基础上,再来求最小生成树就可以了。
那些一开始就没有被加入最小生成树的边,到了暴力枚举又加入很多权值为0的边排在他们前面,就更加不会被包含到最小生成树中了。
Run Time: 0.245s
#define UVa "LT11-3.1151.cpp" //Buy or Build
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
//Global Variables.
const int maxn = 1000 + 5, maxe = maxn*maxn, maxq = 10;
int T, n, q, m;
int x[maxn], y[maxn];
int u[maxe], v[maxe], w[maxe], r[maxe];
int qsize[maxq], qcost[maxq], qcities[maxq][maxn];
vector<int> min_span_tree;
int p[maxn];
int ans;
////
int cmp(int a, int b) { return w[a] < w[b]; }
int calc_w(int a, int b) { return (x[a]-x[b])*(x[a]-x[b]) + (y[a]-y[b])*(y[a]-y[b]); }
int find(int s) { //union-find set
int t = s;
while(s != p[s]) s = p[s];
while(p[t] != s) { //change p along the path
int tmp = p[t];
p[t] = s;
t = tmp;
}
return s;
}
void kruscal() {
min_span_tree.clear();
ans = 0;
for(int i = 0; i < m; i ++) {
int e = r[i];
int x = find(u[e]), y = find(v[e]);
if(x != y) { //include in min-span tree.
p[x] = y;
ans += w[e];
min_span_tree.push_back(e);
}
}
}
void print_bin(int a) {
for(int i = 0; i < q; i ++) {
printf("%d", a%2);
a/=2;
}
printf("\n");
}
int solve() {
for(int s = 1; s < (1<<q); s ++) { //iterating all existing networks.
int tmp = 0;
for(int i = 1; i <= n; i ++) p[i] = i; //reset union-find set.
for(int k = 0; k < q; k ++) if((1<<k) & s){
tmp += qcost[k];
for(int i = 0; i < qsize[k]; i ++){
for(int j = i+1; j < qsize[k]; j ++){
int x = find(qcities[k][i]), y = find(qcities[k][j]);
if(x != y) p[x] = y;
}
}
}
for(int i = 0; i < min_span_tree.size(); i ++) {
int e = min_span_tree[i];
int x = find(u[e]), y = find(v[e]);
if(x != y) {
p[x] = y;
tmp += w[e];
}
}
ans = min(ans, tmp);
}
return 0;
}
int main(){
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &q);
for(int i = 0; i < q; i ++) {
scanf("%d%d", &qsize[i], &qcost[i]);
for(int j = 0; j < qsize[i]; j ++)
scanf("%d", &qcities[i][j]);
}
for(int i = 1; i <= n; i ++) {
scanf("%d%d", &x[i], &y[i]);
p[i] = i;
}
m = 0;
for(int i = 1; i <= n; i ++) {
for(int j = i+1; j <= n; j ++) {
r[m] = m;
u[m] = i;
v[m] = j;
w[m] = calc_w(i, j);
m ++;
}
}
sort(r, r+m, cmp);
kruscal();
solve();
printf("%d\n", ans);
if(T) printf("\n");
}
return 0;
}