按照紫书的思路先求出最小生成树并且记录下相应的边,在枚举选择的套餐,然后更新进行相应的计算即可,具体实现见如下代码:
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
using namespace std;
class assist{
public:
int amount, cost;
vector<int> id;
};
class Point{
public:
int x;
int y;
};
class Edge{
public:
int id1, id2;
int cost;
};
bool compare(const Edge& a, const Edge& b){
return a.cost < b.cost;
}
int parent[1005];
class Solve{
public:
int n, q;
vector<assist> Assist;
vector<Point> point;
vector<Edge> edge;
vector<Edge> res;
int cnt;
void InitParent(){
for (int i = 1; i <= n; i++)
parent[i] = i;
}
int find_root(int x){
int r = x;
while (parent[r] != r){
r = parent[r];
}
while (parent[x] != x){
int t = parent[x];
parent[x] = r;
x = t;
}
return r;
}
int square1(int x,int y){
return (x - y)*(x - y);
}
int MST(){
if (cnt == 0) return 0;
int total = 0;
sort(edge.begin(),edge.end(),compare);
for (int i = 0; i < edge.size(); i++){
int a = edge[i].id1, b = edge[i].id2;
int root_a = find_root(a);
int root_b = find_root(b);
if (root_a != root_b){
parent[root_a] = root_b;
cnt--;
total += edge[i].cost;
}
if (cnt == 0) break;
}
return total;
}
void Init(){
Assist.clear();
point.clear();
edge.clear();
res.clear();
cnt = n - 1;
for (int i = 0; i < q; i++){
assist temp;
cin >> temp.amount >> temp.cost;
for (int j = 0; j < temp.amount; j++){
int id;
cin >> id;
temp.id.push_back(id);
}
Assist.push_back(temp);
}
for (int i = 1; i <= n; i++){//点的下标从1开始
Point temp;
cin >> temp.x >> temp.y;
point.push_back(temp);
}
for (int i = 1; i <= n; i++){
for (int j = i+1; j <= n; j++){
Edge temp;
temp.id1 = i;
temp.id2 = j;
temp.cost = square1(point[i-1].x, point[j-1].x) + square1(point[i-1].y, point[j-1].y);
edge.push_back(temp);
}
}
InitParent();
MST();
}
void Deal(){
Init();
int ans = 1 << 30;
for (int st = 0; st < (1 << q); st++){
int total_cost = 0;
InitParent();
cnt = n - 1;
for (int i = 0; i < q; i++){
if ((1 << i)&st){
total_cost += Assist[i].cost;
int start = Assist[i].id[0];
for (int j = 1; j < Assist[i].id.size(); j++){
int end = Assist[i].id[j];
int root_s = find_root(start);
int root_e = find_root(end);
if (root_e != root_s){
cnt--;
parent[root_e] = root_s;
}
}
}
}
ans = min(ans,total_cost+MST());
}
cout << ans << endl;
}
};
int main(){
int Case;
Solve a;
cin >> Case;
while (Case--){
cin >> a.n >> a.q;
a.Deal();
if (Case) cout << endl;
}
return 0;
}