博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法笔记_180:历届试题 国王的烦恼(Java)
阅读量:6656 次
发布时间:2019-06-25

本文共 3837 字,大约阅读时间需要 12 分钟。

目录

 


1 问题描述

问题描述
  C国由n个小岛组成,为了方便小岛之间联络,C国在小岛间建立了m座大桥,每座大桥连接两座小岛。两个小岛间可能存在多座桥连接。然而,由于海水冲刷,有一些大桥面临着不能使用的危险。
  如果两个小岛间的所有大桥都不能使用,则这两座小岛就不能直接到达了。然而,只要这两座小岛的居民能通过其他的桥或者其他的小岛互相到达,他们就会安然无事。但是,如果前一天两个小岛之间还有方法可以到达,后一天却不能到达了,居民们就会一起抗议。
  现在C国的国王已经知道了每座桥能使用的天数,超过这个天数就不能使用了。现在他想知道居民们会有多少天进行抗议。
输入格式
  输入的第一行包含两个整数n, m,分别表示小岛的个数和桥的数量。
  接下来m行,每行三个整数a, b, t,分别表示该座桥连接a号和b号两个小岛,能使用t天。小岛的编号从1开始递增。
输出格式
  输出一个整数,表示居民们会抗议的天数。
样例输入
4 4
1 2 2
1 3 2
2 3 1
3 4 3
样例输出
2
样例说明
  第一天后2和3之间的桥不能使用,不影响。
  第二天后1和2之间,以及1和3之间的桥不能使用,居民们会抗议。
  第三天后3和4之间的桥不能使用,居民们会抗议。
数据规模和约定
  对于30%的数据,1<=n<=20,1<=m<=100;
  对于50%的数据,1<=n<=500,1<=m<=10000;
  对于100%的数据,1<=n<=10000,1<=m<=100000,1<=a, b<=n, 1<=t<=100000。

 

 

 


2 解决方案

说一下此题题意的理解问题:首先,我要吐槽一下,出题人的语文应该是体育老师教的吧

 

原题描述:

现在C国的国王已经知道了每座桥能使用的天数,超过这个天数就不能使用了。现在他想知道居民们会有多少天进行抗议

输出格式

输出一个整数,表示居民们会抗议的天数

 

看到上面描述,外加题目所给实例输入及输出语句,且要确保每个岛屿都能两两到达

,第一印象就是使用最小生成树Kruskal算法。但是,这里要把边的权值变成负值,相应的最小就是该桥能够使用的天数最长,如此再求得最小生成树中的权值绝对值最小的边,即为居民开始进行抗议的天数。

带着这样的思考方式,提交后只得了10分,还是碰巧对的。

带着疑惑心里,看了一些网友的解答,又把题目读了一遍,提取关键点:居民们会抗议的天数,注意是天数,为此我理解为最小生成树中最大权值和最小权值差的绝对值就是答案。但是,网上相关网友的解答都不是这样计算的。

直到,我看到了文末参考资料一篇网友把题目描述修改了一部分,具体如下:

 

修改后:

现在C国的国王已经知道了每座桥能使用的天数,超过这个天数就不能使用了。现在他想知道居民们一共会发起多少次抗议

输出

  输出一个整数,表示居民们发起抗议的次数

 

把这个天字改为次字,即求取最小生成树中权值不同的个数即为最终所求答案。为此,本题下面先求取最小生成树,然后用HashSet存放权值,最终set集合中元素个数即为最终答案。

下面代码在蓝桥系统中运行超时,具体原因应该是Java语言和C++语言编译运行的性能有关,大部分网友C++写的解答都是使用并查算法,其实Kruskal算法的本质也是并查算法,我用网友C++代码跑的是100分。

 

 

 

具体代码如下:

 

import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.HashSet;import java.util.Scanner;public class Main {    public static int n, m;    public static int[] id;    public static ArrayList
list = new ArrayList
(); public static HashSet
set = new HashSet
(); class MyComparator implements Comparator
{ public int compare(edge arg0, edge arg1) { if(arg0.t > arg1.t) return 1; else if(arg0.t < arg1.t) return -1; return 0; } } static class edge { public int a; public int b; public int t; public edge(int a, int b, int t) { this.a = a; this.b = b; this.t = t; } } public int find(int a) { int root = a; while(id[root] >= 0) { root = id[root]; } int i = 0, k = a; while(k != root) { i = id[k]; id[k] = root; k = i; } return root; } public void union(int a, int b) { int rootA = find(a); int rootB = find(b); if(rootA == rootB) return; int num = id[rootA] + id[rootB]; if(id[rootA] < id[rootB]) { id[rootB] = rootA; id[rootA] = num; } else { id[rootA] = rootB; id[rootB] = num; } } public void kruskal() { Collections.sort(list, new MyComparator()); id = new int[n + 1]; for(int i = 1;i <= n;i++) id[i] = -1; int count = 0; for(int i = 0;i < list.size();i++) { edge p = list.get(i); if(find(p.a) != find(p.b)) { set.add(p.t); union(p.a, p.b); count++; if(count == n - 1) break; } } System.out.println(set.size()); } public static void main(String[] args) { Main test = new Main(); Scanner in = new Scanner(System.in); n = in.nextInt(); m = in.nextInt(); for(int i = 0;i < m;i++) { int a = in.nextInt(); int b = in.nextInt(); int t = in.nextInt(); list.add(new edge(a, b, -1 * t)); } test.kruskal(); }}

 

 

 

 

 

 

 

参考资料:

   1.

 

转载地址:http://gvqto.baihongyu.com/

你可能感兴趣的文章
如何用git reflog和git cherry-pick找回已删除的commit记录
查看>>
关于光驱和硬盘设为主盘的方法
查看>>
解决Linux中分区之后不能创建文件系统
查看>>
VB中的转义字符(回车、换行、Tab等)
查看>>
我的友情链接
查看>>
“Unable to execute dex: Multiple dex files define...” 解决办法
查看>>
redis数据类型
查看>>
CentOS开机简要流程
查看>>
第七周开发日志
查看>>
XenCenter7.5中创建网卡绑定
查看>>
软件测试,需要所有人的努力
查看>>
IO学习总结一
查看>>
Cenots 7.0编译安装libiconv-1.14时的故障
查看>>
如何一次创建大量用户
查看>>
dmidecode+awk搜集内存容量和插槽对应关系
查看>>
手工安装桌面环境;备忘下。
查看>>
mysql简单性能排查
查看>>
Photoshop制作一只可爱的卡通小鸟
查看>>
IBM HP DELL LENOVO服务器接入交换机网络规划
查看>>
Java程序运行时间计算
查看>>