题意:
思路: 算法入门经典358.
AC代码:
不懂这个二进制优化。
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <iostream>
#define ll long long
using namespace std;
const int maxn=1050;
int f[maxn];
struct Edge{
int s,e;
int d;
}p[maxn*maxn];
struct node{
int x,y;
}v[maxn];
int mm;
vector<int>g[10];
int V[maxn];
void init(){
for(int i=1; i<=maxn; i++) f[i]=i;
}
int get(node a,node b){
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(Edge a,Edge b){
return a.d<b.d;
}
int Find(int x){
int r=x;
while(r!=f[r]){
r=f[r];
}
int j=x;
while(f[j]!=r){
int i=f[j];
f[j]=r;
j=i;
}
return r;
}
int kruskal(){
int ss=0;
for(int i=1; i<=mm; i++){
int fx=Find(p[i].s);
int fy=Find(p[i].e);
if(fx!=fy){
ss+=p[i].d;
f[fx]=fy;
}
}
return ss;
}
int main(){
// freopen("2.txt","r",stdin);
int t;
int n,m;
scanf("%d",&t);
while(t--){
int num;
memset(V,0,sizeof(V));
scanf("%d%d",&n,&m);
for(int i=0; i<=m; i++) g[i].clear();
for(int i=0; i<m; i++){
int x;
scanf("%d%d",&num,&V[i]);
for(int j=1; j<=num; j++){
scanf("%d",&x);
g[i].push_back(x);
}
}
for(int i=1; i<=n; i++){
scanf("%d%d",&v[i].x,&v[i].y);
}
mm=0;
for(int i=1; i<=n; i++){
for(int j=i+1; j<=n; j++){
mm++;
p[mm].s=i; p[mm].e=j;
p[mm].d=get(v[i],v[j]);
}
}
init();
sort(p+1,p+mm+1,cmp);
int sum=kruskal();
int c;
for(int i=0; i<(1<<m); i++){
init();
c=0;
for(int j=0; j<m; j++){
if(i & (1<<j)){
c+=V[j];
int xx=Find(g[j][0]);
for(int k=1; k<g[j].size(); k++){
int xy=Find(g[j][k]);
if(xx!=xy){
f[xy]=xx;
}
}
}
}
sum=min(c+kruskal(),sum);
}
printf("%d\n",sum);
if(t) printf("\n");
}
return 0;
}