题意:平面上有N个点(1≤N≤1000),若要新建边,费用是2点的欧几里德距离的平方。另外还有Q个套餐,每个套餐里的点互相联通,总费用为Ci。问让所有N个点连通的最小费用。(2组数据的输出之间要求有换行)

解法:利用二进制枚举套餐,时间复杂度是O(2QN2+N2logN)。关于时间复杂度,枚举:二进制枚举为2Q,Kruskal为ElogE≈E≈N2;边排序:ElogE≈E≈N2。总的相加。

紫书上提到一个优化:不加任何套餐跑一遍MST(最小生成树),没有选的边便删除掉,因为以后加了套餐之后也选不到它。

理解有点困难:由于Kruskal算法中不会进入MST的边是那些两端属于同一个连通分量的边,那么套餐里的点互相连通,相当于在原先MST的图上另外加了几条权值为0的边。这时可能超过N-1条边出现环,那么我们就要割掉权值最大的这个环里的边,留下较小的边。这样的MST就是除了套餐必要的费用之外的权值和最小的了。

P.S.如果比赛时想不明白,那就只能对拍了!

P.P.S.但我不知道为什么优化无论加不加时间都差不多,明明优化使时间复杂度变为了O(2QN+N2logN),2Q≈103,N=103,logN≈10,理应由O(106)变为O(103)啊。

下面附上我的加了优化的代码——

  1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 #include<algorithm>
6 using namespace std;
7 const int N=1010,M=(int)1e6+10,Q=10,X=3010,D=(int)2e6+10;
8 typedef long long LL;
9
10 int n,q,m;
11 int fa[N];
12 struct hp{int c,t;int s[N];}b[Q];
13 struct vert{int x,y;}a[N];
14 struct edge{int x,y,d;}e[M];
15
16 LL mmin(LL x,LL y) {return x<y?x:y;}
17 int sq_dist(int i,int j) {return (a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y);}
18 void ins(int id,int x,int y,int d) {e[id].x=x,e[id].y=y,e[id].d=d;}
19 bool cmp(edge x,edge y) {return x.d<y.d;}
20 int ffind(int x)
21 {
22 if (fa[x]!=x) fa[x]=ffind(fa[x]);
23 return fa[x];
24 }
25 LL MST()
26 {
27 int i,t=0;
28 int cnt=0;//0
29 LL ans=0;
30 sort(e+1,e+1+m,cmp);
31 for (i=1;i<=n;i++) fa[i]=i;
32 for (i=1;i<=m;i++)
33 {
34 int x=e[i].x,y=e[i].y;
35 int xx=ffind(x),yy=ffind(y);
36 if (xx!=yy)
37 {
38 fa[xx]=yy;
39 cnt++,ans+=e[i].d;
40 e[++t]=e[i];
41 if (cnt==n-1) break;
42 }
43 }
44 m=t;
45 return ans;
46 }
47 LL MST_2(int cnt)
48 {
49 int i;
50 LL ans=0;
51 for (i=1;i<=m;i++)
52 {
53 int x=e[i].x,y=e[i].y;
54 int xx=ffind(x),yy=ffind(y);
55 if (xx!=yy)
56 {
57 fa[xx]=yy;
58 cnt++,ans+=e[i].d;
59 if (cnt==n-1) break;
60 }
61 }
62 return ans;
63 }
64 int main()
65 {
66 int T,i,j,k;
67 scanf("%d",&T);
68 while (T--)
69 {
70 scanf("%d%d",&n,&q);
71 for (i=1;i<=q;i++)
72 {
73 scanf("%d%d",&b[i].t,&b[i].c);
74 for (j=1;j<=b[i].t;j++)
75 scanf("%d",&b[i].s[j]);
76 }
77 for (i=1;i<=n;i++)
78 scanf("%d%d",&a[i].x,&a[i].y);
79 m=0;
80 for (i=1;i<=n;i++)
81 for (j=i+1;j<=n;j++)
82 ins(++m,i,j,sq_dist(i,j));
83
84 LL ans=MST();
85 for (i=0;i<(1<<q);i++)//bracelet
86 {
87 for (j=1;j<=n;j++) fa[j]=j;
88 int cnt=0,h=0;
89 for (j=1;j<=q;j++)
90 if (i&(1<<(j-1)))
91 {
92 h+=b[j].c;
93 for (k=2;k<=b[j].t;k++)
94 {
95 int x=b[j].s[1],y=b[j].s[k];
96 int xx=ffind(x),yy=ffind(y);
97 if (xx!=yy) fa[xx]=yy,cnt++;
98 }
99 }
100 ans=mmin(ans,h+MST_2(cnt));
101 }
102 printf("%lld\n",ans);
103 if (T) printf("\n");
104 }
105 return 0;
106 }

【uva 1151】Buy or Build(图论--最小生成树+二进制枚举状态)的更多相关文章

  1. UVa 1151 Buy or Build (最小生成树+二进制法暴力求解)

    题意:给定n个点,你的任务是让它们都连通.你可以新建一些边,费用等于两点距离的平方(当然越小越好),另外还有几种“套餐”,可以购买,你购买的话,那么有些边就可以连接起来, 每个“套餐”,也是要花费的, ...

  2. UVA 1151 Buy or Build MST(最小生成树)

    题意: 在平面上有n个点,要让所有n个点都连通,所以你要构造一些边来连通他们,连通的费用等于两个端点的欧几里得距离的平方.另外还有q个套餐,可以购买,如果你购买了第i个套餐,该套餐中的所有结点将变得相 ...

  3. 紫书 例题 11-3 UVa 1151 (有边集的最小生成树+二进制枚举子集)

    标题指的边集是说这道题的套餐, 是由几条边构成的. 思路是先做一遍最小生成树排除边, 因为如果第一次做没有加入的边, 到后来新加入了很多权值为0的边,这些边肯定排在最前面,然后这条边的前面的那些边肯定 ...

  4. UVa 1151 - Buy or Build(最小生成树)

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  5. UVA 1151 Buy or Build (最小生成树)

    先求出原图的最小生成树,然后枚举买哪些套餐,把一个套餐内的点相互之间边权为0,直接用并查集缩点.正确性是基于一个贪心, 在做Kruskal算法是,对于没有进入最小生成树的边,排序在它前面的边不会减少. ...

  6. UVa 1151 Buy or Build【最小生成树】

    题意:给出n个点的坐标,现在需要让这n个点连通,可以直接在点与点之间连边,花费为两点之间欧几里得距离的平方,也可以选购套餐,套餐中所含的点是相互连通的 问最少的花费 首先想kruskal算法中,被加入 ...

  7. UVA - 1151 Buy or Build (买还是建)(并查集+二进制枚举子集)

    题意:平面上有n个点(1<=n<=1000),你的任务是让所有n个点连通.可以新建边,费用等于两端点欧几里德距离的平方.也可以购买套餐(套餐中的点全部连通).问最小费用. 分析: 1.先将 ...

  8. UVA 1151 Buy or Build (MST最小生成树,kruscal,变形)

    题意: 要使n个点之间能够互通,要使两点直接互通需要耗费它们之间的欧几里得距离的平方大小的花费,这说明每两个点都可以使其互通.接着有q个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需 ...

  9. uva 1151 - Buy or Build poj 2784 Buy or Build(最小生成树)

    最小生成树算法简单 只是增加了一些新的东西,对于需要最小生成树算法 和中 并检查使用的一系列 还有一些更深入的了解. 方法的一些复杂问题 #include<cstdio> #include ...

随机推荐

  1. 天梯赛练习 L3-011 直捣黄龙 (30分) dijkstra + dfs

    题目分析: 本题我有两种思路,一种是只依靠dijkstra算法,在dijkstra部分直接判断所有的情况,以局部最优解得到全局最优解,另一种是dijkstra + dfs,先计算出最短距离以及每个点的 ...

  2. MongoDB备份(mongodump)与恢复(mongorestore)工具实践

    mongodump和mongorestore实践 1.mongodump备份工具 mongodump能够在Mongodb运行时进行备份,它的工作原理是对运行的Mongodb做查询,然后将所有查到的文档 ...

  3. Java开发手册之编程规约

    时隔一年多,再次开始更新博客,各位粉丝们久等了.大家是不是以为我像大多数开发者一样三分钟热度,坚持了一年半载就放弃了,其实不是.在过去的一年时间我学习了<Java编程思想>这本书,因为都是 ...

  4. 【Git】2、Linux快速安装Git环境 & oh-my-zsh

    Linux快速安装Git环境 文章目录 Linux快速安装Git环境 1.Linux安装Git 2.安装zsh 3.安装oh-my-zsh 3.1.安装oh-my-zsh 3.2. 测试验证 4.小结 ...

  5. 摆脱 996——GitHub 热点速览 v.21.03

    作者:HelloGitHub-小鱼干 Twitter 有位程序员总结了本周的 GitHub 中文程序员的看点:国内程序员日常--考公务员.996.抢茅台.刷算法.整健康码.在本期热点速览里,小鱼干收录 ...

  6. kubernets集群的安全防护(下)

    一   集群角色以及集群角色绑定 1.1  前面我们提到过角色以及角色绑定,那么现在为什么会出现集群级别的角色以及角色绑定,作用有如下所示 我们如果需要在所有的命名的空间创建某个角色或者角色绑定的时候 ...

  7. Loadrunner录制脚本与编写脚本的区别

    异同点: 1.录制的和编写的脚本质量上没有区别 2.性能脚本关心的是用户和服务器的数据交互,从这点上来看,录制和编写也没有区别,手动编写脚本也可以写出很真实的脚本 3.能录制的情况下,就录制吧,谁每天 ...

  8. 在Ubuntu18.04下编译出ffmpeg(支持推流H265成rtmp)

    Ubuntu18.04下编译libx264.libx265.libfdk_aac和ffmpeg 一.编译x264库 二.编译fdk-aac库 三.编译x265库 四.编译FFmpeg源码 五.设置环境 ...

  9. 1.8V转3V,1,8V转3.3V电源芯片的规格书参数

    1.8V电平如何稳压稳定输出3V或者3.3V,就需要用到1.8V转3V,1,8V转3.3V电源芯片,就PW5100(低功耗,外围简单),PW5200A是可调输出电压,可以输出电压根据外围电阻来设置命令 ...

  10. Mybatis plus通用字段自动填充的最佳实践总结

    在进行持久层数据维护(新增或修改)的时候,我们通常需要记录一些非业务字段,比如:create_time.update_time.update_by.create_by等用来维护数据记录的创建时间.修改 ...