将1号点从图中去掉过后,图会形成几个连通块,那么我们首先可以在这些连通块内部求最小生成树。

假设有\(tot\)个连通块,那么我们会从1号点至少选\(tot\)个出边,使得图连通。这时我们贪心地选择最小的,这应该都很好懂。

因为题目中的要求是度数不超过\(s\),那么也就是说我们可以从1号点出发,再加入\(s-tot\)条边,因为可能这些边的边权比连通块中的某些边边权小,那么替换过后答案肯定最优。

具体替换方法为:如果当前顶点度数为\(k\),我们现在要向\(k+1\)的度数扩展,我们肯定要枚举所有没用到过的出边,因为只会添加一条边,那么就会形成一个环。单独考虑一条边\((1,x)\),肯定会选择将\(1\)到\(x\)路径上面边权最大的边给替换掉。那么我们可以枚举所有的情况,最后取min,就能得到\(k+1\)度的最优解。最后一次类推就行了。。。。如果向\(k+1\)度扩展得不到更优解时,直接break掉就行了。

具体思路就是这样。。。。但是代码细节稍微有点多。

因为求最小生成树时会利用到边的信息,以及最后会考虑1的每个出边,所以我先把边给标号,并且用了一个\(v[i]\)来保存\(i\)号结点所有的出边,这样就会方便一些。

细节见代码吧:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <iostream>
  5. #include <string>
  6. #include <map>
  7. #include <vector>
  8. using namespace std;
  9. typedef long long ll;
  10. const int N = 35;
  11. int t;
  12. int n, s;
  13. struct Edge{
  14. int u, v, w;
  15. }e[N * N];
  16. vector <int> v[N], vec;
  17. bool vis[N], used[N * N], check[N * N];
  18. int tot;
  19. ll ans ;
  20. void dfs(int x) {
  21. vis[x] = 1;
  22. for(auto i : v[x]) {
  23. int to = e[i].v, u = e[i].u;
  24. if(to == x) to = u ;
  25. if(to != 1 && !check[i]) {
  26. vec.push_back(i) ;
  27. check[i] = 1;
  28. }
  29. if(!vis[to] && to != 1) dfs(to) ;
  30. }
  31. }
  32. bool cmp(int a, int b) {
  33. return e[a].w < e[b].w;
  34. }
  35. int f[N], d[N], ee[N];
  36. int find(int x) {
  37. return f[x] == x ? x : f[x] = find(f[x]) ;
  38. }
  39. int insert(int i) {
  40. int x = e[i].u, y = e[i].v;
  41. int fx = find(x), fy = find(y) ;
  42. if(fx != fy) {
  43. f[fx] = fy;
  44. ans += e[i].w;
  45. used[i] = 1;
  46. return 1;
  47. } else return 0;
  48. }
  49. void dfs2(int x) {
  50. vis[x] = 1;
  51. for(auto i : v[x]) {
  52. int u = e[i].u, to = e[i].v;
  53. if(to == x) to = u;
  54. if(!vis[to] && used[i]) {
  55. if(e[i].w > d[x]) {
  56. d[to] = e[i].w;
  57. ee[to] = i;
  58. } else {
  59. d[to] = d[x] ;
  60. ee[to] = ee[x] ;
  61. }
  62. dfs2(to) ;
  63. }
  64. }
  65. }
  66. int main() {
  67. cin >> t;
  68. while(t--) {
  69. ans = 0;
  70. //处理输入
  71. cin >> n;
  72. for(int i = 1; i < N; i++) v[i].clear() ;
  73. map <string ,int> mp;
  74. memset(check, 0, sizeof(check)) ;
  75. memset(used, 0, sizeof(used)) ;
  76. mp["Park"] = 1;
  77. int num = 1;
  78. tot = 0;
  79. string s1, s2;
  80. for(int i = 1; i <= n; i++) {
  81. int dis;
  82. cin >> s1 >> s2 >> dis;
  83. if(mp.find(s1) == mp.end()) mp[s1] = ++num;
  84. if(mp.find(s2) == mp.end()) mp[s2] = ++num;
  85. e[i] = Edge{mp[s1], mp[s2], dis} ;
  86. v[mp[s1]].push_back(i) ;
  87. v[mp[s2]].push_back(i) ;
  88. }
  89. cin >> s;
  90. //在每个连通块内求最小生成树
  91. for(int i = 1; i < N; i++) f[i] = i;
  92. memset(vis, 0, sizeof(vis)) ;
  93. for(int i = 2; i <= num; i++) {
  94. if(!vis[i]) {
  95. vec.clear() ;
  96. tot++;
  97. dfs(i);
  98. sort(vec.begin(), vec.end(), cmp) ;
  99. for(auto i : vec) insert(i) ;
  100. }
  101. }
  102. //选出最小的边让树连通
  103. vec.clear() ;
  104. for(auto i : v[1]) vec.push_back(i) ;
  105. sort(vec.begin(), vec.end(), cmp) ;
  106. int l = vec.size(), k;
  107. for(int i = 0; i < tot; i++) {
  108. for(k = 0; k < l; k++) {
  109. int ok = insert(vec[k]) ;
  110. if(ok) break ;
  111. }
  112. }
  113. //贪心换边
  114. int cnt = s - tot;
  115. while(cnt--) {
  116. memset(d, 0, sizeof(d)) ;
  117. memset(vis, 0, sizeof(vis)) ;
  118. dfs2(1);
  119. int mn = 0, f = -1;
  120. for(int j = 0; j < l; j++) {
  121. int i = vec[j] ;
  122. if(used[i]) continue ;
  123. int x = e[i].u, y = e[i].v, to;
  124. if(x == 1) to = y;
  125. else to = x;
  126. if(e[i].w - d[to] < mn) {
  127. mn = e[i].w - d[to] ;
  128. f = i;
  129. }
  130. }
  131. if(f == -1) break ;
  132. int i = f ;
  133. int x = e[i].u, y = e[i].v, to;
  134. if(x == 1) to = y;
  135. else to = x;
  136. used[i] = 1;
  137. used[ee[to]] = 0;
  138. ans += mn;
  139. }
  140. cout << "Total miles driven: ";
  141. cout << ans << '\n';
  142. if(t) cout << '\n' ;
  143. }
  144. return 0;
  145. }
  146. /*
  147. 13
  148. Park 1 9
  149. Park 2 10
  150. Park 3 10
  151. Park 4 10
  152. Park 5 10
  153. Park 6 10
  154. Park 7 10
  155. 1 2 11
  156. 1 4 13
  157. 2 3 12
  158. 4 5 14
  159. 5 6 14
  160. 6 7 13
  161. 6
  162. */

UVA1537 Picnic Planning(思维+最小生成树)的更多相关文章

  1. poj1639,uva1537,uvalive2099,scu1622,fzu1761 Picnic Planning (最小限制生成树)

    Picnic Planning Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 10742   Accepted: 3885 ...

  2. POJ1639 - Picnic Planning

    原题链接 Description 给出一张个点的无向边权图并钦定点,求使得点的度不超过的最小生成树. Solution 首先无视掉与相连的所有边,原图会变成若干互不连通的个块.对每个块分别求MST,再 ...

  3. POJ 1639 Picnic Planning 最小k度生成树

    Picnic Planning Time Limit: 5000MS   Memory Limit: 10000K Total Submissions:11615   Accepted: 4172 D ...

  4. POJ1639 Picnic Planning (限制入度最小生成树)

    节点1是有度数限制的,把节点1去掉,就会形成若干个连通块,在每个连通块内部求最小生成树(prim算法实现),并求出每个连通块与1相连的最短的边,这样形成了初始状态的生成树. 假设(1,x)这条边没在生 ...

  5. POJ-1639 Picnic Planning 度数限制最小生成树

    解法参考的论文:https://wenku.baidu.com/view/8abefb175f0e7cd1842536aa.html 觉得网上的代码好像都是用邻接矩阵来实现的,觉得可能数据量大了会比较 ...

  6. 【POJ 1639】 Picnic Planning (最小k度限制生成树)

    [题意] 有n个巨人要去Park聚会.巨人A和先到巨人B那里去,然后和巨人B一起去Park.B君是个土豪,他家的停车场很大,可以停很多车,但是Park的停车场是比较小.只能停k辆车.现在问你在这个限制 ...

  7. POJ 1639 Picnic Planning(最小度限制生成树)

    Description The Contortion Brothers are a famous set of circus clowns, known worldwide for their inc ...

  8. poj1639 Picnic Planning 最小度数限制生成树

    题意:若干个人开车要去park聚会,可是park能停的车是有限的,为k.所以这些人要通过先开车到其它人家中,停车,然后拼车去聚会.另外,车的容量是无限的,他们家停车位也是无限的. 求开车总行程最短. ...

  9. poj 1639 Picnic Planning 度限制mst

    https://vjudge.net/problem/POJ-1639 题意: 有一群人,他们要去某一个地方,每个车可以装无数个人,给出了n条路,包含的信息有路连接的地方,以及路的长度,路是双向的,但 ...

随机推荐

  1. 【Spring Boot学习之九】缓存支持

    环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 一.Spring Boot Cache以及整合EhCacheSpring从3.1开始定义了org.springfram ...

  2. Linux 就该这么学 CH03 管道符、重定向和环境变量

    0 概述 1 输入输出重定向 重定向技术有5种模式: 标准覆盖输出重定向 标准追加输出重定向 错误覆盖输出重定向 错误追加输出重定向 输入重定向 输入重定向是将文件导入到命令中. 输出重定向是将输入到 ...

  3. 031 SSM综合练习07--数据后台管理系统--用户详情查询

    1.用户详情查询流程分析 2.代码实现 (1)user-list.jsp页面部分代码 点击jsp页面中的详情按钮,发送请求到UserController.java <!--数据列表--> ...

  4. 彻底理解Runnable和Thread的区别

    昨天去面试,面试官问了一个问题:Runnable和Thread有什么区别,因为针对这个问题以前有背过,并且网上大多数都是这些结论,所以脱口而出: 1.Thread有单继承的问题: 2.Runnable ...

  5. 测试函数——python编程从入门到实践

    测试函数 学习测试,得有测试的代码.下面是一个简单的函数: name_function.py def get_formatted_name(first, last): ""&quo ...

  6. Django框架第七篇(模型层)--多表操作:一对多/多对多增删改,跨表查询(基于对象、基于双下划线跨表查询),聚合查询,分组查询,F查询与Q查询

    一.多表操作 一对多字段的增删改(book表和publish表是一对多关系,publish_id字段) 增  create publish_id 传数字   (publish_id是数据库显示的字段名 ...

  7. PB 将菜单中的部分按钮设置为某些页面不可选中

    if tab_1.selectedtab = 9 or tab_1.selectedtab = 10 then uo_toolbarstrip.of_enable(uo_toolbarstrip.of ...

  8. CapsLock魔改大法——变废为宝实现高效编辑

    前言 CapsLock,也就是键盘左边中间那个大写锁定.平时很少会用到,跟shift功能重复不谈,更多的时候还会带来各种额外的麻烦. 一直以来的都是一个非常碍事讨厌的存在.就是这么一个垃圾键,偏偏却占 ...

  9. js 不同浏览器的类型判断 navigator.userAgent

    一.通过navigator.userAgent来进行浏览器类型判断 // 判断浏览器内核.手机系统等,使用 browser.userAgent.mobile var browser = { userA ...

  10. linux上文件的上传和下载

    现整理一篇linux上文件的上传和下载 第一种方式就是在windos上安装工具 如: 工具如何使用我就不赘述了,easy 第二种方式就是使用liux的命令(首先是文件上传) 上传文件(首先创建文件夹如 ...