https://vjudge.net/problem/UVA-1151

题意:

平面上有n个点,你的任务是让所有n个点连通。为此,你可以新建一些边,费用等于两个端点的距离平方和。另外还有q个套餐可以购买,如果你购买了第i个套餐,该套餐中的所有结点都变得相互连通,第i个套餐的花费为Ci。

思路:

这道题比较容易超时。可能需要用到并查集的路径压缩,我下面的代码就是用了路径压缩,不然要超时。也是看了别人的代码才知道还有这种省时间的做法。

先介绍一下路径压缩吧:

如果并查集像一字长蛇这样排列的话,寻找起来就比较费时间,但如果像图2一样的话,一下子就可以找到根了。压缩的方法也是挺简单的。

  1. int r = x;
  2. while (r != p[r]) r = p[r];
  3. int i = x, j;
  4. while (p[i] != r)
  5. {
  6. j = p[i];
  7. p[i] = r;
  8. i = j;
  9. }

题目的做法就像紫书上说的那样,先不考虑套餐算一遍,然后枚举套餐的方法,这里的话二进制枚举法非常方便。

  1. #include<iostream>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<vector>
  5. using namespace std;
  6.  
  7. const int maxn = + ;
  8.  
  9. int n, m, q, cnt;
  10. int p[maxn];
  11. vector<int> g[]; //方案集合
  12. int c[]; //方案价格
  13.  
  14. //边
  15. struct node
  16. {
  17. int u;
  18. int v;
  19. int dist;
  20. }edge[maxn*maxn];
  21.  
  22. //点
  23. struct node2
  24. {
  25. int x, y;
  26. }a[maxn];
  27.  
  28. int find(int x)
  29. {
  30. //return p[x] == x ? x : find(p[x]); 用这个会超时
  31. //路径压缩
  32. int r = x;
  33. while (r != p[r]) r = p[r];
  34. int i = x, j;
  35. while (p[i] != r)
  36. {
  37. j = p[i];
  38. p[i] = r;
  39. i = j;
  40. }
  41. return r;
  42. }
  43.  
  44. bool cmp(node a, node b)
  45. {
  46. return a.dist < b.dist;
  47. }
  48.  
  49. //计算距离平方和
  50. int cacl_dist(node2 a, node2 b)
  51. {
  52. return (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y);
  53. }
  54.  
  55. void init()
  56. {
  57. for (int k = ; k <= n; k++) p[k] = k;
  58. }
  59.  
  60. int Kruskal()
  61. {
  62. int num = ;
  63. int ans = ;
  64. for (int i = ; i < cnt ; i++)
  65. {
  66. int x = find(edge[i].u);
  67. int y = find(edge[i].v);
  68. if (x != y)
  69. {
  70. p[x] = y;
  71. ans += edge[i].dist;
  72. num++;
  73. }
  74. if (num == n - ) return ans;
  75. }
  76. return ans;
  77. }
  78.  
  79. void solve()
  80. {
  81. init();
  82. int ans = Kruskal();
  83. //二进制枚举方案
  84. for (int i = ; i < ( << q); i++)
  85. {
  86. init();
  87. int cost = ;
  88. for (int j = ; j < q; j++)
  89. {
  90. if (i & ( << j))
  91. {
  92. cost += c[j];
  93. int x = find(g[j][]);
  94. for (int k = ; k < g[j].size(); k++)
  95. {
  96. int y = find(g[j][k]);
  97. if (x != y)
  98. p[y] = x;
  99. }
  100. }
  101. }
  102. ans = min(cost + Kruskal(), ans);
  103. }
  104. printf("%d\n", ans);
  105. }
  106.  
  107. int main()
  108. {
  109. //freopen("D:\\txt.txt", "r", stdin);
  110. int T, t, s, kase=;
  111. scanf("%d", &T);
  112. while (T--)
  113. {
  114. if (++kase > ) printf("\n");
  115. scanf("%d%d", &n, &q);
  116.  
  117. //存储方案
  118. for (int i = ; i < q; i++)
  119. {
  120. g[i].clear();
  121. scanf("%d", &t);
  122. scanf("%d", &c[i]);
  123. for (int j = ; j < t; j++)
  124. {
  125. scanf("%d", &s);
  126. g[i].push_back(s);
  127. }
  128. }
  129.  
  130. for (int i = ; i <= n; i++)
  131. scanf("%d%d", &a[i].x, &a[i].y);
  132.  
  133. //存储边
  134. cnt = ;
  135. for (int i = ; i <= n;i++)
  136. for (int j = i + ; j <= n; j++)
  137. {
  138. edge[cnt].u = i;
  139. edge[cnt].v = j;
  140. edge[cnt].dist = cacl_dist(a[i], a[j]);
  141. cnt++;
  142. }
  143. sort(edge, edge + cnt, cmp);
  144. solve();
  145. }
  146. return ;
  147. }

UVa 1151 买还是建的更多相关文章

  1. UVA 1151 买还是建(最小生成树)

    买还是建 紫书P358 [题目链接]买还是建 [题目类型]最小生成树 &题解: 这题真的心累,看了3天,最后照着码还是wa,先放lrj代码,以后再看吧 &代码: // UVa1151 ...

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

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

  3. 洛谷 题解 UVA1151 【买还是建 Buy or Build】

    [题意] 平面上有\(n(n<=1000)\)个点,你的任务是让所有n个点联通.为此,你可以新建一些边,费用等于两个端点的欧几里得距离平方.另外还有\(q(q<=8)\)个套餐可以购买,如 ...

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

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

  5. UVA 1151

    /* 题意:有n个点,现在需要联通所有,有q种套餐可以选择, 当然套餐之外也可以自己添加边,意为达到最短距离. 题意很明显,不知道需要使用哪一种套餐, 那么需要枚举每一种套餐的情况. 然后再进行对比. ...

  6. uva 1151(最小生成树,枚举子集)

    题意:平面上有n个点(1<=N<=1000),你的任务是让所有n个点连通,为此,你可以新建一些边,费用等于两个端点的欧几里得距离的平方.另外还有q(0<=q<=8)个套餐,可以 ...

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

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

  8. UVa 1151 (枚举 + MST) Buy or Build

    题意: 平面上有n个点,现在要把它们全部连通起来.现在有q个套餐,如果购买了第i个套餐,则这个套餐中的点全部连通起来.也可以自己单独地建一条边,费用为两点欧几里得距离的平方.求使所有点连通的最小费用. ...

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

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

随机推荐

  1. Prometheus+Grafana+Altermanager搭建监控系统

    基本概念 Prometheus 时间序列化数据库,我的理解就是将数据打上标签,以时间维度存储.后面有机会在深入研究. Prometheus架构如下: Grafana Prometheus中存储的数据, ...

  2. 007-jdk1.6版本新特性

    一.JDK1.6 名称:Mustang(野马) 发布日期:2006-04 新特性: 1.1.AWT新增加了两个类:Desktop和SystemTray[忽略] 前者可以用来打开系统默认浏览器浏览指定的 ...

  3. 十天精通CSS3(11)

    Media Queries——媒体类型(一) 随着科学技术不断的向前发展,网页的浏览终端越来越多样化,用户可以通过:宽屏电视.台式电脑.笔记本电脑.平板电脑和智能手机来访问你的网站.尽管你无法保证一个 ...

  4. POD类型

    POD类型 POD全称Plain Old Data.通俗的讲,一个类或结构体通过二进制拷贝后还能保持其数据不变,那么它就是一个POD类型. C++11将POD划分为两个基本概念的合集,即:平凡的和标准 ...

  5. ssm返回jsonp数据格式

    为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数 ...

  6. SqlAlchemy个人学习笔记完整汇总-转载

    使用 sqlalchemy 有3种方式: 方式1, 使用raw sql; 方式2, 使用SqlAlchemy的sql expression; 方式3, 使用ORM.   前两种方式可以统称为 core ...

  7. keras搭建深度学习模型的一些小tips

    定义模型两种方法:  1.sequential 类仅用于层的线性堆叠,这是目前最常用的网络架构 2.函数式API,用于层组成的有向无环图,让你可以构建任意形式的架构 from keras import ...

  8. unity3d-射线(Ray)

    射线Ray 射线是一个点向另外一个点发生的一条线,一旦与其他模型发生碰撞,他将停止发射.注意这条件是逻辑上的,界面上看不到. 一般使用射线判断是否发射至某个游戏对象上或者获得鼠标点击的游戏对象等. 用 ...

  9. SpringMyBatisDay01

    1.Spring简介 Spring是一个开源轻量级应用开发框架,其目的是用于简化企业级应用程序的开发,降低侵入性Spring提供IOC和AOP功能,可以将组件(就是类)之间的耦合度降至最低,解耦,便于 ...

  10. Python 迭代器切片

    函数itertools.islice() 正好适用于在迭代器和生成器上做切片操作 >>> def count(n): ... while True: ... yield n ... ...