目录

1 问题描述

2 解决方案

 


1 问题描述

问题描述

Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路。道路被用来连接N个牧场,牧场被连续地编号为1到N。每一个牧场都是一个奶牛的家。FJ计划除去P条道路中尽可能多的道路,但是还要保持牧场之间 的连通性。你首先要决定那些道路是需要保留的N-1条道路。第j条双向道路连接了牧场Sj和Ej(1 <= Sj <= N; 1 <= Ej <= N; Sj != Ej),而且走完它需要Lj的时间。没有两个牧场是被一条以上的道路所连接。奶牛们非常伤心,因为她们的交通系统被削减了。你需要到每一个奶牛的住处去安慰她们。每次你到达第i个牧场的时候(即使你已经到过),你必须花去Ci的时间和奶牛交谈。你每个晚上都会在同一个牧场(这是供你选择的)过夜,直到奶牛们都从悲伤中缓过神来。在早上 起来和晚上回去睡觉的时候,你都需要和在你睡觉的牧场的奶牛交谈一次。这样你才能完成你的 交谈任务。假设Farmer John采纳了你的建议,请计算出使所有奶牛都被安慰的最少时间。

输入格式

第1行包含两个整数N和P。

接下来N行,每行包含一个整数Ci。

接下来P行,每行包含三个整数Sj, Ej和Lj。

输出格式
输出一个整数, 所需要的总时间(包含和在你所在的牧场的奶牛的两次谈话时间)。
样例输入
5 7
10
10
20
6
30
1 2 5
2 3 5
2 4 12
3 4 17
2 5 15
3 5 6
样例输出
176
数据规模与约定

5 <= N <= 10000,N-1 <= P <= 100000,0 <= Lj <= 1000,1 <= Ci <= 1,000。


2 解决方案

首先说一下这个题目的问题以及题意的理解:

问题:

题目给出的输入样例数据,其中顶点数为5,边数为7,可是样例数据中的实际只有6条边的数据,这个有点坑啊...,后来提交代码,看了一下第一组测试数据,这组数据就是样例数据,其第7条边数据为 4  5  7。

期题意中样例输入输出数据应为:

样例输入

5 7
10
10
20
6
30
1 2 5
2 3 5
2 4 12
3 4 17
2 5 15
3 5 6

4 5 12

样例输出

176

题意理解:初步读这题,为了理解题意也是读了三四遍,其中:你每个晚上都会在同一个牧场(这是供你选择的)过夜,直到奶牛们都从悲伤中缓过神来。这句话我也是醉了,为了描述一个题目,也不要弄得这么文艺呀。该题传到意思核心:即首先找到n个牧场的最小生成树,然后,选择其中一个开始进行遍历,最后要回到起点点牧场。

分析到这里,大家要注意,这里有一个小坑,那就是怎么寻找最小生成树?即是直接使用牧场之间的距离行走时间Lj来确定最小生成树,还是要把每个牧场交谈时间Ci也算入最小生成树的判断?

我刚开始做的时候,是使用Li来确定最小生成树,然后选择其中Ci最小的牧场开始出发,最后回到出发点,会发现对于题目中所给的样例输入数据测试,其输出为178,而不是题目中的176。

然后,我经过检查发现2 4 12,4 5 12这两条边选择不同其最终的输出样例也不同,顶点2的Ci为10,顶点5的Ci为30,然后自己测试了一次,如果最小生成树选择4 5 12,样例输出为178,如果选择2 4  12样例输出为176。这里面影响的原因就是构造的最小生成树不对。

所以,到了这里我们再分析一下,从顶点1到顶点2所耗费时间为2*L12 + C1 + C2,这里为什么会有2 * L12呢?因为题意中说明从某一个牧场出发后,最终还要返回这个牧场,说明每一条边要行走2次,即一去一回。那么又有新的问题了,为什么C1和C2不乘以2呢?我们在看看最小生成树,就会发现,如果一个牧场,只有一条边连接,其顶点值计算一次,如果有2条边,就计算2次,3条边就计算3次,依次类推。那么在公式里2 * L12 + C1 + C2就很好的说明了一点,那就是一个牧场有几条边,那它的顶点就被加了几次。

这里就可以理解为顶点C1到C2的边的权值为 2*L12 + C1 + C2,然后,利用这个权值求取最小生成树。

到了这里问题已经解决了百分之九十五了,最后,再选择一个牧场顶点Ci最小的值,用这么最小Ci加上最小生成树的权值和就可以得到最终的结果啦。

此处还有一点问题就是,下面我的代码在练习系统中的最终评分为70分,
具体原因为:运行超时。

然后,我用同样方法的C语言代码在系统里运行后,测试结果为100分(PS:此处代码可以看出文末给出的参考资料)。可以看出Java和C/C++运行时间有很大差异啊。(PS:如有同学路过,发现不是语言运行性能的原因,而是选用方法不当造成运行超时的话,希望不吝赐教呀~)

下面代码中,我是使用Kruskal算法实现,具体原理可以参考楼主的另一篇博客:算法笔记_066:Kruskal算法详解(Java)

具体代码如下:

  1. import java.util.Scanner;
  2.  
  3. public class Main {
  4.  
  5. class edge {
  6. public int a;
  7. public int b;
  8. public int value;
  9.  
  10. edge(int a, int b, int value) {
  11. this.a = a;
  12. this.b = b;
  13. this.value = value;
  14. }
  15. }
  16.  
  17. public void edgeSort(edge[] A){
  18. if(A.length > 1) {
  19. edge[] leftA = getHalfEdge(A, 0);
  20. edge[] rightA = getHalfEdge(A, 1);
  21. edgeSort(leftA);
  22. edgeSort(rightA);
  23. mergeEdgeArray(A, leftA, rightA);
  24. }
  25. }
  26.  
  27. public edge[] getHalfEdge(edge[] A, int judge) {
  28. edge[] half;
  29. if(judge == 0) {
  30. half = new edge[A.length / 2];
  31. for(int i = 0;i < A.length / 2;i++)
  32. half[i] = A[i];
  33. } else {
  34. half = new edge[A.length - A.length / 2];
  35. for(int i = 0;i < A.length - A.length / 2;i++)
  36. half[i] = A[A.length / 2 + i];
  37. }
  38. return half;
  39. }
  40.  
  41. public void mergeEdgeArray(edge[] A, edge[] leftA, edge[] rightA) {
  42. int i = 0;
  43. int j = 0;
  44. int len = 0;
  45. while(i < leftA.length && j < rightA.length) {
  46. if(leftA[i].value < rightA[j].value) {
  47. A[len++] = leftA[i++];
  48. } else {
  49. A[len++] = rightA[j++];
  50. }
  51. }
  52. while(i < leftA.length) A[len++] = leftA[i++];
  53. while(j < rightA.length) A[len++] = rightA[j++];
  54. }
  55. //获取节点a的根节点
  56. public int find(int[] id, int a) {
  57. int x, r, k;
  58. r = a;
  59. while(id[r] >= 0) r = id[r];
  60. k = a;
  61. while(k != r) {
  62. x = id[k];
  63. id[k] = r;
  64. k = x;
  65. }
  66. return r;
  67. }
  68. //合并a节点所在树和b节点所在树
  69. public void union(int[] id, int a, int b) {
  70. int ida = find(id, a);
  71. int idb = find(id, b);
  72. int num = id[ida] + id[idb];
  73. if(id[ida] < id[idb]) {
  74. id[idb] = ida;
  75. id[ida] = num;
  76. } else {
  77. id[ida] = idb;
  78. id[idb] = num;
  79. }
  80. }
  81. //获取题意最终结果
  82. public void getMinSpanTree(edge[] A, int[] valueN) {
  83. int sum = 0;
  84. int[] id = new int[valueN.length];
  85.  
  86. for(int i = 0;i < valueN.length;i++)
  87. id[i] = -1;
  88. edgeSort(A);
  89. int count = 0;
  90. for(int i = 0;i < A.length;i++) {
  91. int a = A[i].a;
  92. int b = A[i].b;
  93. int ida = find(id, a - 1);
  94. int idb = find(id, b - 1);
  95. if(ida != idb) {
  96. sum += A[i].value;
  97. count++;
  98. union(id, a - 1, b - 1);
  99. }
  100. if(count >= valueN.length - 1)
  101. break;
  102. }
  103.  
  104. int minValueN = valueN[0];
  105. for(int i = 0;i < valueN.length;i++) {
  106. if(minValueN > valueN[i]) {
  107. minValueN = valueN[i];
  108. }
  109. }
  110. sum += minValueN;
  111. System.out.println(sum);
  112. }
  113.  
  114. public static void main(String[] args){
  115. Main test = new Main();
  116. Scanner in = new Scanner(System.in);
  117. int n = in.nextInt();
  118. int p = in.nextInt();
  119. if(n > 10000 || n < 5)
  120. return;
  121. if(p > 100000 || p < n - 1)
  122. return;
  123. int[] valueN = new int[n];
  124. for(int i = 0;i < n;i++)
  125. valueN[i] = in.nextInt();
  126. edge[] A = new edge[p];
  127. for(int i = 0;i < p;i++) {
  128. int a = in.nextInt();
  129. int b = in.nextInt();
  130. int value = in.nextInt() * 2 + valueN[a - 1] + valueN[b - 1];
  131. A[i] = test.new edge(a, b, value);
  132. }
  133. test.getMinSpanTree(A, valueN);
  134. }
  135. }

参考资料:

1.算法训练 安慰奶牛(最小生成树)

算法笔记_067:蓝桥杯练习 算法训练 安慰奶牛(Java)的更多相关文章

  1. 算法笔记_107:蓝桥杯练习 算法提高 学霸的迷宫(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 学霸抢走了大家的作业,班长为了帮同学们找回作业,决定去找学霸决斗.但学霸为了不要别人打扰,住在一个城堡里,城堡外面是一个二维的格子迷宫,要 ...

  2. 算法笔记_096:蓝桥杯练习 算法提高 求最大值(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 给n个有序整数对ai bi,你需要选择一些整数对 使得所有你选定的数的ai+bi的和最大.并且要求你选定的数对的ai之和非负,bi之和非负 ...

  3. 算法笔记_081:蓝桥杯练习 算法提高 矩阵乘法(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 有n个矩阵,大小分别为a0*a1, a1*a2, a2*a3, ..., a[n-1]*a[n],现要将它们依次相乘,只能使用结合率,求最 ...

  4. 算法笔记_077:蓝桥杯练习 K好数(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数.求L位K进制数中K好数的数目.例如K = 4, ...

  5. 算法笔记_106:蓝桥杯练习 算法提高 周期字串(Java)

    目录 1 问题描述 2 解决方案 2.1 第一印象解法(80分) 2.2 借鉴网友解法(100分)   1 问题描述 问题描述 右右喜欢听故事,但是右右的妈妈总是讲一些“从前有座山,山里有座庙,庙里有 ...

  6. 算法笔记_102:蓝桥杯练习 算法提高 快乐司机(Java)

    目录 1问题描述 2 解决方案   1 问题描述 问题描述 "嘟嘟嘟嘟嘟嘟 喇叭响 我是汽车小司机 我是小司机 我为祖国运输忙 运输忙" 这是儿歌“快乐的小司机”.话说现在当司机光 ...

  7. 算法笔记_099:蓝桥杯练习 算法提高 排列数(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 0.1.2三个数字的全排列有六种,按照字母序排列如下: 012.021.102.120.201.210 输入一个数n 求0~9十个数的全排 ...

  8. 算法笔记_061:蓝桥杯练习 字串统计(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 给定一个长度为n的字符串S,还有一个数字L,统计长度大于等于L的出现次数最多的子串(不同的出现可以相交),如果有多个,输出最长的,如果仍然 ...

  9. 算法笔记_123:蓝桥杯第七届省赛(Java语言B组部分习题)试题解答

     目录 1 凑算式 2 方格填数 3 四平方和   1 凑算式 凑算式 B DEF A + --- + ------- = 10 C GHI (如果显示有问题,可以参见[图1.jpg]) 这个算式中A ...

随机推荐

  1. dubbo 官方参考手册~备案(防止哪天阿里一生气把dubbo给删除了)

          首页  ||  下载  ||  用户指南  ||  开发者指南  ||  管理员指南  ||  培训文档  ||  常见问题解答  ||  发布记录  ||  发展路线  ||  社区 E ...

  2. ubuntu 16.04 LTS 安装 teamviewer 13

    背景介绍 由于需要做现场的远程支持,经协商后在现场的服务器上安装TeamViewer 以便后续操作. 本来以为很简单的一件事,谁知却稍微费了一番周折  :( 记录下来,希望提醒自己的同时也希望能够帮到 ...

  3. javascript继承之借用构造函数(二)

    //简单的函数调用 function Father() { this.nums= [1,2]; } function Son() { Father.call(this);//调用超类型,完成son继承 ...

  4. C# CPU,硬盘,mac地址灯本地信息查询

    public class Computer { public static string CpuID; //1.cpu序列号 public static string MacAddress; //2. ...

  5. uva-193-图染色-枚举

    题意:n个节点,可用描成黑色或者白色,黑节点和黑节点不能相连,问最多描出多少黑节点 #include <iostream> #include <stdio.h> #includ ...

  6. ckeditor源码编辑模式,添加style、javascript内容丢失的解决

    我使用ckeditor 我在编辑的使用源码编辑,保存内容包含javascript.style标签的时候,数据库中有javascript.style标签 , 输入到页面也可以执行,但是我再次编辑的时候就 ...

  7. JS的prototype和__proto__、constructor

    看了JS的prototype和__proto__这篇文章,才感觉很清晰了,对于原型这块,以前经常把这些属性弄不清楚, 明白了之后保存下整理下: prototype: 是函数的一个属性(每个函数都有一个 ...

  8. Win7 系统还原

    Win7 由于某种原因,第二天开机不正常,桌面配置丢失,桌面上的文档不见了. 这种情况不要怕. 可以在启动界面F8,进入系统还原,然后选择某个时间点还原成功!!! 错误描述: Windows 不能加载 ...

  9. socket 网络连接基础

    socket 客户端 import socket 1.client = socket.socket()  # socket.TCP/IP 选择连接的类型,默认为本地连接 2.client.connec ...

  10. jstatd - Virtual Machine jstat Daemon

    jstatd [options] 参数:options 命令行参数,可以按任何顺序,但如果有多余的或者中有互斥的参数,最后制定的那个参数将有优先权 options: -nr 当一个存在的RMI Reg ...