题意:n个城市架设通信线路,要使各个城市相互联通,两城市之间的费用为两城市的欧几里得距离。此外有q个套餐,套餐中有几个城市联通,套餐会有一些费用,问怎样使总费用最小。
分析:可枚举使用哪些套餐,再求最小生成树,但边数很大,会T,可不要套餐求一次最小生成树,得到的n-1条边即使选择套餐,其他边也必从这n-1条边中选择,这样就大大降低了遍历边的数目.
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#define inf 10000000
#define pi acos(-1.0)
#define eps 1e-8
#define seed 131
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair<int,int> pa;
const int maxn=100005;
int n,q;
int cost[8];
int st[8][1000];
int cood[1005][2];
int p[1005];
struct Edge
{
int a,b;
int dis;
bool operator<(const Edge& e)const
{
return dis<e.dis;
}
}edge[500000];
Edge line[1005];
int ans;
void solve(int cnt);
int find(int x)
{
return p[x]==x?x:p[x]=find(p[x]);
}
bool un(int i,int j)
{
int x=find(i);
int y=find(j);
if(x==y)
return false;
p[x]=y;
return true;
}
int main()
{
int t;
scanf("%d",&t);
for(int cas=0;cas<t;cas++)
{
if(cas!=0)
printf("\n");
scanf("%d%d",&n,&q);
for(int i=0;i<q;i++)
{
scanf("%d%d",&st[i][0],&cost[i]);
for(int j=1;j<=st[i][0];j++)
scanf("%d",&st[i][j]);
}
for(int i=1;i<=n;i++)
scanf("%d%d",&cood[i][0],&cood[i][1]);
int num=0;
for(int i=1;i<n;i++)
{
for(int j=i+1;j<=n;j++)
{
edge[num].a=i;
edge[num].b=j;
edge[num++].dis=(cood[i][0]-cood[j][0])*(cood[i][0]-cood[j][0])+(cood[i][1]-cood[j][1])*(cood[i][1]-cood[j][1]);
}
}
sort(edge,edge+num);
for(int i=1;i<=n;i++)
p[i]=i;
int op=0;
ans=0;
for(int i=0;i<num;i++)
{
if(un(edge[i].a,edge[i].b))
{
ans+=edge[i].dis;
line[op].a=edge[i].a;
line[op].b=edge[i].b;
line[op].dis=edge[i].dis;
op++;
if(op==n-1)
break;
}
}
for(int i=1;i<(1<<q);i++)
solve(i);
printf("%d\n",ans);
}
return 0;
}
void solve(int cnt)
{
int cos=0;
for(int i=1;i<=n;i++)
p[i]=i;
int rt=0;
for(int i=0;i<q;i++)
{
if(cnt&(1<<i))
{
for(int j=1;j<st[i][0];j++)
{
if(un(st[i][j],st[i][j+1]))
rt++;
}
cos+=cost[i];
}
}
if(rt==n-1)
{
ans=min(ans,cos);
return;
}
for(int i=0;i<n;i++)
{
if(un(line[i].a,line[i].b))
{
rt++;
cos+=line[i].dis;
if(rt==n-1)
break;
}
}
ans=min(ans,cos);
return;
}