题目链接
先求出不买套餐的最小生成树的边
然后枚举选择哪些套餐,将套餐中的边权置为 \(0\), 和原先最小生成树的边重新进行 \(kruscal\)
而原先选不到的边,权值大于套餐和最小生成树的边,后来一定也选不到
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000100;
const int INF = 1000000007;
int T, n, q, cnt, ans;
int c[10];
int x[maxn], y[maxn];
vector<int> Gc[10];
struct Edge{
int u, v, w;
bool operator < (const Edge& o) const{
return w < o.w;
}
}e[maxn];
vector<Edge> E, nE;
int par[maxn], ran[maxn];
int find(int x){
return par[x] == x ? x : par[x] = find(par[x]);
}
void unite(int x, int y){
x = find(x), y = find(y);
if(x == y) return;
if(ran[x] < y){
par[x] = y;
} else{
par[y] = x;
if(ran[x] == ran[y]) ++ran[x];
}
}
void kruscal(){
for(int i = 1 ; i <= n ; ++i) par[i] = i, ran[i] = 1;
int tot = 0;
for(int i = 1 ; i <= cnt ; ++i){
if(find(e[i].u) != find(e[i].v)){
unite(e[i].u, e[i].v);
++tot;
E.push_back(e[i]);
if(tot == n - 1){
break;
}
}
}
}
int use[maxn];
void dfs(int d){
if(d == q + 1){
nE.clear();
int res = 0;
for(auto u : E){
nE.push_back(u);
}
for(int i = 1 ; i <= q ; ++i){
if(use[i]){
res += c[i];
int u = -1;
for(auto v : Gc[i]){
Edge ne;
if(u != -1){
ne.u = u;
ne.v = v;
ne.w = 0;
nE.push_back(ne);
u = v;
} else{
u = v;
}
}
}
}
sort(nE.begin(), nE.end());
for(int i = 1 ; i <= n ; ++i) par[i] = i, ran[i] = 1;
int tot = 0;
for(auto p : nE){
if(find(p.u) != find(p.v)){
unite(p.u, p.v);
++tot;
res += p.w;
if(tot == n - 1){
ans = min(ans, res);
break;
}
}
}
return;
}
use[d] = 1;
dfs(d + 1);
use[d] = 0;
dfs(d + 1);
}
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
scanf("%d", &T);
int flag = 0;
while(T--){
if(flag){
printf("\n");
}
flag = 1;
cnt = 0;
for(int i = 1 ; i <= q ; ++i) Gc[i].clear();
E.clear();
memset(use, 0, sizeof(use));
ans = INF;
scanf("%d%d", &n, &q);
for(int i = 1 ; i <= q ; ++i){
int u, v;
scanf("%d", &u);
scanf("%d", &c[i]);
for(int j = 1 ; j <= u ; ++j){
scanf("%d", &v);
Gc[i].push_back(v);
}
}
for(int i = 1 ; i <= n ; ++i){
scanf("%d%d", &x[i], &y[i]);
}
for(int i = 1 ; i <= n ; ++i){
for(int j = i + 1 ; j <= n ; ++j){
++cnt;
e[cnt].u = i, e[cnt].v = j;
e[cnt].w = (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
}
}
sort(e + 1, e + 1 + cnt);
kruscal();
dfs(1);
printf("%d\n", ans);
}
return 0;
}