减治法解决八枚硬币问题/假币问题(JAVA)----二分,三分,不知轻重的情况

八枚硬币问题


在八枚外观相同的硬币中,有一枚是假币,并且已知假币与真币的重量不同,但不知道假币与真币相比较轻还是较重。可以通过一架天平来任意比较两组硬币,设计一个高效的算法来检测出这枚假币。

我们先假设一个条件:已知假币比真币轻


二分查找算法实现:时间复杂度(O(log(以2为底n的对数)))

思路:把n枚硬币分成两堆,每堆有枚硬币,如果n为奇数的话,就留下一枚额外的硬币,然后把两堆硬币放在天平上。如果两堆硬币重量相同,那么放在旁边的硬币就是假币;否则我们可以用同样的方式对较轻的一堆硬币进行处理,这堆硬币中一定包含那枚假币。注意,即使我们把硬币分成了两个子集,但在每次称重之后,我们只需要解决一个规模为原来一半的问题。所以这是一个减治算法而不是一个分治算法。


public class Main {static int[] a = {2, 2, 2, 2, 2, 2, 1, 2};public static void main(String[] args) {int l = 0;int r = a.length-1;System.out.println(f2(l, r));}private static int f2(int l, int r) {int n = r - l + 1;int mid = (l+r) / 2;if(n == 1) {return l;}/*** n为总个数,mid为中值* n为偶数,则将n枚硬币分成两堆数量相等的硬币,对轻的一堆迭代称重* n为奇数,留下一枚硬币,对n-1枚硬币按偶数继续操作* */if (n % 2 == 0) {if (sum(l, mid) == sum(mid+1, r)) {return l - 1;} else if (sum(l, mid) < sum(mid+1, r)){return f2(l, mid);} else {return f2(mid+1, r);}} else {return f2(l+1, r);}}/*** 获取指定区域内硬币的重量* */private static int sum(int l, int r) {int sum = 0;for (int i = l; i <= r; i++) {sum += a[i];}return sum;}
}


三分查找算法实现:时间复杂度(O(log(以3为底n的对数)))

思路:将n枚硬币分成三组,前两组有组硬币,其余的硬币作为第三组,将前两组硬币放到天平上,如果它们的重量相同,则假币一定在第三组中,用同样的方法对第三组进行处理;如果前两组的重量不同,则假币一定在较轻的那一组中,用同样的方法对较轻的那组硬币进行处理。这也是一个减治算法。

public class Main {static int[] a = {2, 2, 2, 2, 2, 2, 1, 2};public static void main(String[] args) {int l = 0;int r = a.length-1;System.out.println(f3(l, r));}private static int f3(int l, int r) {int n = r - l + 1;int x;if(n == 1) {return l;}/*** n为总个数* 将n分成n/3, n/3, n-2(n/3)三堆硬币* 对前两堆称重,相等则对第三堆继续操作,不相等则对轻的一堆继续操作* */if (n % 3 == 0) {x = n / 3;} else {x = n / 3 + 1;return f3(l+1, r);}int mid1 = l + x - 1;int mid2 = mid1 + x;if (sum(l, mid1) == sum(mid1+1, mid2)) {return f3(mid2+1, r);} else if (sum(l, mid1) < sum(mid1+1, mid2)){return f3(l, mid1);} else {return f3(mid1+1, mid2);}}/*** 获取指定区域内硬币的重量* */private static int sum(int l, int r) {int sum = 0;for (int i = l; i <= r; i++) {sum += a[i];}return sum;}
}

二分查找算法适用于单调的一个函数,即数组序列要么升序,要么降序

而三分查找算法使用于凸函数,常用来求极值问题。

在假币问题中,三分查找在n较大的情况下,效率是优于二分查找的。

最复杂的情况

下面来回到最开始的问题,在不知道假币轻重的情况下,我们通过下面的算法来实现,其时间复杂度为O(log(以2为底n的对数))

相比来说,这种情况思考起来比较复杂,但是好在逻辑清楚,只要理解了思路,算法还是好实现的,下面我们来举一个例子,假设有八枚硬币,其中有一枚硬币是假币。但是我们不知道假币是比真币重还是轻。先把八枚硬币编号,分别表示为a,b,c,d,e,f,g,h,从八枚硬币中任取六枚a,b,c,d,e,f,在天平两端各放三枚进行比较。假设a,b,c三枚放在天平的一端,d,e,f三枚放在天平的另一端,可能出现三种比较结果:

⑴ a+b+c>d+e+f

⑵ a+b+c=d+e+f

⑶ a+b+c<d+e+f

若a+b+c>d+e+f,可以肯定这六枚硬币中必有一枚为假币,同时也说明g、h为真币。这时可将天平两端各去掉一枚硬币,假设去掉c、f,同时将天平两端的硬币各换一枚,假设硬币b、e作了互换,然后进行第二次比较,比较的结果同样可能有三种:

① a+e>d+b:这种情况表明天平两端去掉硬币c、f且硬币b、e互换后,天平两端的轻重关系保持不变,从而说明了假币必然是a,d中的一个,这时我们只要用一枚真币(例如h)和a进行比较,就能找出假币。若a>h,则a是较重的假币;若a=h,则d为较轻的假币;不可能出现a<h的情况。(为什么?很简单,因为我们判断了a,d中有一个假币那么e,b都是真币,则e=d。而a+e>d+b可以推出a>d,所以不管a是真是假都不可能出现a<h情况出现)

② a+e=d+b:此时天平两端由不平衡变为平衡,表明假币一定在去掉的两枚硬币c,f中,同样用一枚真币(例如h)和c进行比较,若c>h,则c是较重的假币;若c=h,则f为较轻的假币;不可能出现c<h的情况。

③ a+e<d+b:此时表明由于两枚硬币b,e的对换,引起了两端轻重关系的改变,那么可以肯定b或e中有一枚是假币,同样用一枚真币(例如h)和b进行比较,若b>h,则b是较重的假币;若b=h,则e为较轻的假币;不可能出现b<h的情况。

public class Main {static int[] a = {2, 2, 2, 2, 2, 2, 1, 2};static int flag = 0;public static void main(String[] args) {int p;if (sum(0, 2) == sum(3, 5)) {p = fp(6, 7);} else if (sum(0, 2) > sum(3, 5)){if (a[0] + a[4] > a[3] + a[1]) {p = fp(0, 3);} else if (a[0] + a[4] == a[3] + a[1]) {p = fp(2, 5);} else {p = fp(1, 4);}} else {if (a[0] + a[4] > a[3] + a[1]) {p = fp(1, 4);} else if (a[0] + a[4] == a[3] + a[1]) {p = fp(2, 5);} else {p = fp(0, 3);}}if (flag == 1) {System.out.println("假币轻,为第" + p + "枚");} else {System.out.println("假币重,为第" + p + "枚");}}private static int fp(int l, int r) {int H, L;int x = (l+1) % 8;if(a[l] > a[r]) {H = l;L = r;} else {H = r;L = l;}if (a[H] > a[x]) {flag = 1;return H;} else {flag = -1;return L;}}/*** 获取指定区域内硬币的重量* */private static int sum(int l, int r) {int sum = 0;for (int i = l; i <= r; i++) {sum += a[i];}return sum;}
}






本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/569795.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

减治法在查找算法中的应用(JAVA)--折半查找

减治法在查找算法中的应用 折半查找&#xff1a;(时间复杂度O(log以2为底n的对数)) 对于有序数组的查找来说&#xff0c;折半查找是一种非常高效的算法&#xff0c;其基本原理为&#xff1a;比较查找键k和数组中间元素a[m]&#xff0c;如果相等&#xff0c;算法结束&#xff…

牛客寒假算法基础集训营2 A处女座的签到题

处女座的签到题 链接&#xff1a;https://ac.nowcoder.com/acm/contest/327/A 题目描述 平面上有n个点&#xff0c;问&#xff1a;平面上所有三角形面积第k大的三角形的面积是多少?输入描述: 第一行T&#xff0c;表示样例的个数。对于每一组样例&#xff0c;第一行两个整数n和…

减治法解决约瑟夫斯问题(JAVA)

减治法在查找算法中的应用问题背景&#xff1a;据说著名犹太历史学家 Josephus有过以下的故事&#xff1a;在罗马人占领乔塔帕特后&#xff0c;39 个犹太人与Josephus及他的朋友躲到一个洞中&#xff0c;39个犹太人决定宁愿死也不要被敌人抓到&#xff0c;于是决定了一个自杀方…

从NetCore报错到MySql安全

从NetCore报错到MySql安全 原文:从NetCore报错到MySql安全之前项目在测试服务器上的一些接口时不时会报出下面的错误&#xff1a;&#xff08;采用Abp框架&#xff09; "SocketException: 你的主机中的软件中止了一个已建立的连接。 STACK TRACE: at MySqlConnector.Pr…

减治法在查找算法中的应用(JAVA)--快速查找

减治法在查找算法中的应用 快速查找&#xff1a;选择问题是求一个n个数列表的第k个最小元素的问题&#xff0c;这个数k被称为顺序统计量。对于k1或kn来说&#xff0c;这并没有什么意义&#xff0c;我们通常会要找出这样的元素&#xff1a;该元素比列表中一半元素大&#xff0…

JavaScript中使用Json

转载于:https://www.cnblogs.com/lyonwu/p/10368989.html

减治法在查找算法中的应用(JAVA)--二叉查找树的查找、插入、删除

减治法在查找算法中的应用二叉查找树的查找与插入&#xff1a; 二叉排序树或者是一棵空树&#xff0c;或者是具有下列性质的二叉树&#xff1a;&#xff08;1&#xff09;若左子树不空&#xff0c;则左子树上所有结点的值均小于或等于它的根节点的值&#xff1b; &#xff08;…

Navicat Premium试用期破解方法(转)

转载网址https://blog.csdn.net/Jason_Julie/article/details/82864187 1、按步骤安装Navicat Premium&#xff0c;如果没有可以去官网下载&#xff1a;http://www.navicat.com.cn/download/navicat-premium 2、安装好后下载激活文件&#xff1a;https://pan.baidu.com/s/1kVgT…

减治法在排序算法中的应用(JAVA)--插入排序

一、减治法在排序算法中的应用 插入排序&#xff1a;时间复杂度O(n^2)&#xff0c;虽然和选择、冒泡在最坏的情况下时间复杂度相同&#xff0c;但是插排平均性能在比自身的最差性能快一倍&#xff0c;所以相比选择、冒泡来说&#xff0c;插排要领先于二者。 public class Main…

减治法在求解拓扑排序问题中的应用(JAVA)--有向无环图

减治法在求解拓扑排序问题中的应用 拓扑排序&#xff1a;对于一个有向无环图来说&#xff0c;如果我们能够按照次序列出顶点&#xff0c;使得对于每条边来说&#xff0c;边的起始顶点总是排在边的结束顶点之前&#xff0c;那么这个过程就称为拓扑排序&#xff0c;拓扑排序有解…

Java中string.equalsIgnoreCase(0)与0.equalsIgnoreCase(string)的区别:

string.equalsIgnoreCase("0")&#xff1a;如果string为null,会抛出java.lang.NullPointerException异常。 "0".equalsIgnoreCase(string)&#xff1a;即使string为null也不会抛出异常。 所以一般如果判断一个字符串与一个常量是否相等的时候&#xff0c;应…

减治法在生成全排列中的应用(JAVA)--回溯、Johnson-Trotter算法、自字典序

减治法在生成组合对象问题中的应用 在深入浅出讲算法思想--蛮力法思想分析及应用这篇文章的最优解问题中中已经初步讲解了这类应用&#xff0c;下面我们将使用减治法再次思考这类问题。 1、全排列问题&#xff0c;在数学中求解一个n个数组合的全排列问题会产生n&#xff01;…

减治法在生成子集问题中的应用(JAVA)--递归、二进制反射格雷码

减治法在生成组合对象问题中的应用 生成子集问题&#xff1a;经典的背包问题就是求解一个最优子集的问题&#xff0c;这里我们来讨论一个更简单的问题。对于任意一个集合来说&#xff0c;它都存在2^n个子集&#xff08;一个集合所有的子集集合称为幂集&#xff09;。 1&…

【第九课】MriaDB密码重置和慢查询日志

目录 1、如何进行修改MariaDB的密码2、Mariadb的慢查询日志1、如何进行修改MariaDB的密码 记得root密码的修改方式&#xff1a; [rootlocalhost ~]# mysqladmin -uroot -p123456 password "123123" [rootlocalhost ~]# mysql -uroot -p Enter password: ERROR 1045 …

减治法解决俄式乘法问题(JAVA)

以上是在《算法设计与分析基础》一书中给出的定义。 这种算法只包括折半、加倍、相加这几个操作&#xff0c;在计算时&#xff0c;不需要用九九乘法表 。 同时&#xff0c;这个方法每次都会将计算的规模减少&#xff0c;运用了减治的思想 public class Main {public static…

1.需要对txt存放的测试数据做去重处理,代码如下

采用集合去重&#xff0c;在新文件里逐行写入&#xff0c;达成目的 old_file "D:/testdata/memberId.txt" #old result_file "D:/testdata/memberId_new.txt" #new lines_seen set() out_file open(result_file, "w") f open(old_file, &q…

减治法解决尼姆(Nim)游戏/拈游戏问题(JAVA)

尼姆游戏是一种两个人玩的回合制数学策略游戏。游戏者轮流从一堆棋子&#xff08;一共有好几堆&#xff0c;一次只能从其中一堆拿。&#xff09;&#xff08;或者任何道具&#xff09;中取走一个或者多个&#xff0c;最后不能再取的就是输家。当指定相应数量时&#xff0c;一堆…

jquery中$(document).ready()和window.onload的区别

在Jquery里面&#xff0c;我们可以看到两种写法:$(function(){}) 和$(document).ready(function(){}) 这两个方法的效果都是一样的&#xff0c;都是在dom文档树加载完之后执行一个函数&#xff08;注意&#xff0c;这里面的文档树加载完不代表全部文件加载完&#xff09;。 $(d…

蛮力法在排序算法中的应用(JAVA)--选择排序、冒泡排序

蛮力法在排序算法中的应用 对于一个排序问题&#xff0c;我们能想到的最简单的排序方法就是选择和冒泡 1、选择排序&#xff1a;时间复杂度O(n^2) public class Main {public static void main(String[] args) {int[] a {89, 45, 68, 90, 29, 34, 17};int min;for (int i 0…

PyCherm的常用快捷键总结

、Ctrl Enter&#xff1a;在下方新建行但不移动光标&#xff1b; 2、Shift Enter&#xff1a;在下方新建行并移到新行行首&#xff1b; 3、Ctrl /&#xff1a;注释(取消注释)选择的行&#xff1b; 4、Ctrl Alt L&#xff1a;格式化代码(与QQ锁定热键冲突&#xff0c;关闭Q…