uva 1151 Buy or Build 克鲁斯卡尔+二进制枚举

来源:互联网 发布:java catch中抛出异常 编辑:程序博客网 时间:2024/05/02 16:39
题意:平面上有n个点每个点都有一个坐标,现在要在这些点之间修路,使全部点连通,修路有两种方式,费用也不同,直接在两点间修建,费用为两点间欧几里得距离的平方,或直接购买已经连通的连通块,都有对应的费用,求最小费用,注意输出格式,稍不注意就是wrong answer
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define Min(a,b) a<b?a:busing namespace std;int n,q;const int maxn = 1010;int f[maxn];struct point{int x,y;}pt[1001];struct Tc{int num,price;int Set[maxn];}tc[9];struct edge{int u,v,w;}e[maxn*maxn];int cnt;void add(int a,int b,int dist){e[cnt].u=a;e[cnt].v=b;e[cnt++].w=dist;}int dist(int a,int b){return (pt[a].x-pt[b].x)*(pt[a].x-pt[b].x)+(pt[a].y-pt[b].y)*(pt[a].y-pt[b].y);}int find(int x){return f[x]==x?x:f[x]=find(f[x]);}bool cmp(edge a,edge b){return a.w<b.w;}int MST(){int ans=0,num=0;for(int i=0;i<cnt;i++){int x=find(e[i].u);int y=find(e[i].v);if(x!=y){f[x]=y;num++;ans+=e[i].w;}if(num>=n-1)break;}return ans;}int main(){int t,fir=1;;long long ans;scanf("%d",&t);while(t--){cnt=0;ans=(1<<30);scanf("%d%d",&n,&q);for(int i=1;i<=n;i++)f[i]=i;for(int i=0;i<q;i++){int num,price;scanf("%d",&tc[i].num);scanf("%d",&tc[i].price);for(int j=0;j<tc[i].num;j++)scanf("%d",&tc[i].Set[j]);}for(int i=1;i<=n;i++)scanf("%d%d",&pt[i].x,&pt[i].y);for(int i=1;i<=n-1;i++)for(int j=i+1;j<=n;j++){int d=dist(i,j);add(i,j,d);}sort(e,e+cnt,cmp);for(int i=0;i<(1<<q);i++)//空集 i =0  ,不购买 ,直接生成最小生成树 {int d=0;for(int j=1;j<=n;j++)f[j]=j;for(int j=0;j<q;j++){if(i&(1<<j)){d+=tc[j].price;for(int k=1;k<tc[j].num;k++){int xx=find(tc[j].Set[0]);//将枚举边集加入到生成树的集合中 int yy = find(tc[j].Set[k]);f[xx]=yy;}}}int xxx=MST();ans = Min(ans,(long long)d+xxx);}printf("%lld\n",ans);        if(t)printf("\n");}}


0 0
原创粉丝点击