基础代码不再赘述,直接进行算法分析。
#已知当m(假币数量)大于2后,我们不再采用三分法,而是采用二分法
一.n为偶数
分析可知二分情况如下
一假币堆 二假币堆
三假币堆 无假币堆
可知此时直接二分,省去称重的一次,因为一定不会平衡
此时我们只知道两个堆总数相等,但是否仍然为偶数或者更细节不得而知所以在此讨论
(1)n%8==0
此时我们假设n=8m,划分n为m1 m2 m3 m4 m5 m6 m7 m8
首先称量m1 m2与m3 m4
平衡则为无假币堆或者二假币堆的1 1排列型,且另一堆不用秤都知道不平衡(因为一定是奇数假币堆)A类
不平衡则称量m5 m6与m7 m8,平衡则与A类相同
不平衡则说明,(1234)和(5678)组合为一假币堆和二假币堆 且二假币堆为2 0排列型 B类
A类时,继续称量m1与m2,平衡则均为无假币堆 a
a类时,知道了另一堆(5678)为三假币堆,继续执行m=3算法。
不平衡则均为单假币堆 b
b类时,(12)(34)(5678)均为一假币堆,执行m=1算法,得 到所有假币位置
B类时,目前已知为一假币堆和二假币堆且二假币堆为2 0排列型
可以知道两者在二分情况下都不会平衡,但是,二分后一定会形成两个无假币堆
假设情况为 无 1 无 2 数量均为n/4
此时互相称量最坏情况下要秤3次才能得到两个无假币组平衡的结果
得到平衡结果后,得到了两组平衡组,和剩下两组一假币堆和二假币堆
此时重点只在于区分一假币堆和二假币堆(其实一直都判别不了)
再次使用虚拟货币法,随便将一堆的重量*2,另一堆的重量加上已知的无假币堆
public static boolean ChengAddVSCopy(int a, int b, int c, int n, List<Coin> coins) {//a,c为两假币和无假币组的起始下标,b为一假币组的起始下标,n为同样的数量
int sum1 = 0, sum2 = 0;
for (int i = coins.get(a - 1).getId(), j = 0; j < n; i++, j++)
sum1 += coins.get(i - 1).getValue();
for (int i = coins.get(c - 1).getId(), j = 0; j < n; i++, j++)
sum1 += coins.get(i - 1).getValue();
for (int i = coins.get(b - 1).getId(), j = 0; j < n; i++, j++)
sum2 += coins.get(i - 1).getValue();
frequency++;
sum2 = sum2 * 2;
return sum1 == sum2;
}
则此时形成了二假币堆和二假币堆或者四假币堆和一假币堆
称重可以进行判决,平衡则翻倍堆为一假币堆,叠加堆为二假币堆
不平衡则翻倍堆为二假币堆,叠加堆位一假币堆
各自执行m=2与m=1算法可以得到剩下三枚假币的位置
if (n % 8 == 0) {
boolean flag1 = Cheng(a, a + n / 4, n / 4, coins);
if (flag1) {//说明称量组为1+1或者无假币堆
boolean flag2 = Cheng(a, a + n / 8, n / 8, coins);
if (flag2) {//为无假币堆
ThreeHuaFen(a + n / 2, n / 2, coins);
} else {//1+1+1
OneHuaFen(a, n / 4, coins);
OneHuaFen(a + n / 4, n / 4, coins);
OneHuaFen(a + n / 2, n / 2, coins);
}
} else {
boolean flag11 = Cheng(a + n / 2, a + n / 4 * 3, n / 4, coins);
if (flag11) {//说明称量组为1+1或者无假币堆
boolean flag2 = Cheng(a + n / 2, a + n / 8 * 5, n / 8, coins);
if (flag2) {//为无假币堆
ThreeHuaFen(a, n / 2, coins);
} else {//1+1+1
OneHuaFen(a, n / 2, coins);
OneHuaFen(a + n / 2, n / 4, coins);
OneHuaFen(a + n / 4 * 3, n / 4, coins);
}
} else {//1+2且2为2+0,注意这里的顺序不一定,1和2谁在前谁在后不一定
//此时只要二分,就能得到两个无假币堆和1+2,
boolean flag21 = Cheng(a, a + n / 2, n / 4, coins);
if (flag21) {
boolean flag3 = ChengAddVSCopy(a + n / 4, a + n / 4 * 3, a, n / 4, coins);
if (flag3) {
TwoHuaFen(a + n / 4, n / 4, coins);
OneHuaFen(a + n / 4 * 3, n / 4, coins);
} else {
TwoHuaFen(a + n / 4 * 3, n / 4, coins);
OneHuaFen(a + n / 4, n / 4, coins);
}
} else {
boolean flag22 = Cheng(a, a + n / 4 * 3, n / 4, coins);
if (flag22) {
boolean flag3 = ChengAddVSCopy(a + n / 4, a + n / 2, a, n / 4, coins);
if (flag3) {
TwoHuaFen(a + n / 4, n / 4, coins);
OneHuaFen(a + n / 2, n / 4, coins);
} else {
TwoHuaFen(a + n / 2, n / 4, coins);
OneHuaFen(a + n / 4, n / 4, coins);
}
} else {
boolean flag23 = Cheng(a + n / 4, a + n / 2, n / 4, coins);
if (flag23) {
boolean flag3 = ChengAddVSCopy(a, a + n / 4 * 3, a + n / 4, n / 4, coins);
if (flag3) {
TwoHuaFen(a, n / 4, coins);
OneHuaFen(a + n / 4 * 3, n / 4, coins);
} else {
TwoHuaFen(a + n / 4 * 3, n / 4, coins);
OneHuaFen(a, n / 4, coins);
}
} else {
boolean flag3 = ChengAddVSCopy(a, a + n / 2, a + n / 4, n / 4, coins);
if (flag3) {
TwoHuaFen(a, n / 4, coins);
OneHuaFen(a + n / 2, n / 4, coins);
} else {
TwoHuaFen(a + n / 2, n / 4, coins);
OneHuaFen(a, n / 4, coins);
}
}
}
}
}
}
(2)n%4==0
此时我们假设n=4m,划分n为m1 m2 m3 m4(m默认为奇数)
继续明确,(12)与(34)是一定不会平衡的
称量m1与m2,平衡则(12)为无假币堆或者二假币堆的1 1排列型 A
不平衡则二分秤另一堆(34),平衡则与上相同
不平衡则说明组合(12)(34)为一假币堆和二 假币堆且二假币堆为2 0排列型 B
由于此时m1已经不能二分,所以无法继续用二分的方法判断,但是仍然可以解决
A情况时,从m1m2堆中拿两枚硬币(这里选择首尾),称量
1 2 xx xxxxx xxx xxx n/2-1 n/2
A。平衡——真币+真币或者假币+假币此时需要分别取两枚硬币(继续首尾),称量
1。平衡——真币+真币或者假币+假币此时称量两次得到的两组硬币(1与2),得到的结果
a。平衡——一共取得了4枚真币,此时m1-1后为偶数,二分称量
boolean flag41 = Cheng(a+1, a + 1+(n/2-2)/4,(n/2-2)/4 , coins);
平衡则m1,m2均为无假币堆,m3+m4执行三假币算法
不平衡则m1,m2均为一假币堆,m3+m4也为一假币堆,执行算法
b。不平衡——前后取出了2真2假币,此堆为二假币堆,先对下的大的一假币堆 (n-4)执行m=1算法,最后得到假币情况后,再对这个4币堆进行求二假币
2。不平衡——真币+假币,之前取出两枚假币的可能性消失了,知道了之前一定是两枚真币。此时其变为了一假币堆,所以将n/2-4枚钱币的一假币堆执行m=1算法,最后得到假币情况后再回头将这一枚假币判断。至于剩下的一假币堆则执行m=1算法
B。不平衡——真币+假币
直接提出这两枚,剩下的进行m=2算法,最后处理这两枚。
B情况时,将m1 m2幻视为m3 m4做的是一样的处理
else if (n % 4 == 0) {
boolean flag1 = Cheng(a, a + n / 4, n / 4, coins);
if (flag1) {//说明称量组为1+1或者无假币堆
boolean flag11 = Cheng(a, a + n / 2 - 1, 1, coins);//一半的首尾取一枚
if (flag11) {
boolean flag21 = Cheng(a + 1, a + n / 2 - 2, 1, coins);//再从首尾取一枚
if (flag21) {//仍然平衡
boolean flag31 = Cheng(a, a + 1, 1, coins);
if (flag31) {
boolean flag41 = Cheng(a+1, a + 1+(n/2-2)/4,(n/2-2)/4 , coins);
if(flag41){//左大堆整体都是无假币的
ThreeHuaFen(a+n/2,n/2,coins);
}else {
OneHuaFen(a+2,(n/2-4)/2,coins);
OneHuaFen(a+2+(n/2-4)/2,(n/2-4)/2,coins);
OneHuaFen(a+n/2,n/2,coins);
}
} else {//有一次取出了两枚假币,此时有4枚需要处理
List<Coin> TemCoins = new ArrayList<>();
TwoLink(a+2,a+n/2,n/2-4,n/2,coins,TemCoins);
OneHuaFen(1, n - 4, TemCoins);
SpecialChuLiTwoInFour(a, a + n/2 - 2, coins);//特殊的处理函数,有一次取的是两枚假币
}
} else {//取的不平衡,出现了假币,排除无假币堆情况,且已知第一次一定是2真币
truecoin=coins.get(a-1);
OneHuaFen(a + 2, n / 2 - 4, coins);
OneHuaFen(a + n / 2, n / 2 , coins);
TwoChuLiOneInTwo(a+1, a+n/2-2, coins);
}
} else {//刚开始就不平衡
List<Coin> TemCoins = new ArrayList<>();
TwoLink(a+1,a+n/2,n/2-2,n/2,coins,TemCoins);
TwoHuaFen(1, n - 2, TemCoins);
ThreeChuLiOneInTwo(a, a + n/2-1, coins);
}
} else {//换组
boolean flag11 = Cheng(a + n / 2, a + n / 4 * 3, n / 4, coins);
if (flag11) {//说明称量组为1+1或者无假币堆
//一半首尾取一枚
boolean flag21 = Cheng(a+n/2, a + n - 1, 1, coins);
if (flag21) {
boolean flag31 = Cheng(a+n/2+1, a + n - 2, 1, coins);//再取一枚
if(flag31){
boolean flag41 = Cheng(a+n/2, a +n/2+1, 1, coins);
if (flag41) {
truecoin=coins.get(a+n/2);
boolean flag51 = Cheng(a+n/2+1, a +n/2+1+(n/2-2)/4,(n/2-2)/4 , coins);
if(flag51){//右大堆整体都是无假币的
ThreeHuaFen(a,n/2,coins);
}else {
OneHuaFen(a,n/2,coins);
OneHuaFen(a+n/2+2,(n/2-4)/2,coins);
OneHuaFen(a+n/2+2+(n/2-4)/2,(n/2-4)/2,coins);
}
} else {//有一次取出了两枚假币,此时有4枚需要处理
List<Coin> TemCoins = new ArrayList<>();
TwoLink(a,a+n/2+2,n/2,n/2-4,coins,TemCoins);
OneHuaFen(1, n - 4, TemCoins);
SpecialChuLiTwoInFour(a+n/2, a + n - 2, coins);//特殊的处理函数,有一次取的是两枚假币
}
}else{
OneHuaFen(a, n / 2, coins);
OneHuaFen(a + n / 2+2, n / 2-4 , coins);
TwoChuLiOneInTwo(a+n/2+1, a + n - 2, coins);
}
} else {
OneHuaFen(a, n / 2, coins);
OneHuaFen(a + n / 2+1, n / 2-2 , coins);
TwoChuLiOneInTwo(a+n/2, a+n-1, coins);
}
} else {//1+2且2为2+0,注意这里的顺序不一定,1和2谁在前谁在后不一定
//此时只要二分,就能得到两个无假币堆和1+2,
//首先去找无假币堆
boolean flag21 = Cheng(a, a + n / 2, n / 4, coins);
if (flag21) {
boolean flag3 = ChengAddVSCopy(a + n / 4, a + n / 4 * 3, a, n / 4, coins);
if (flag3) {
TwoHuaFen(a + n / 4, n / 4, coins);
OneHuaFen(a + n / 4 * 3, n / 4, coins);
} else {
TwoHuaFen(a + n / 4 * 3, n / 4, coins);
OneHuaFen(a + n / 4, n / 4, coins);
}
} else {
boolean flag22 = Cheng(a, a + n / 4 * 3, n / 4, coins);
if (flag22) {
boolean flag3 = ChengAddVSCopy(a + n / 4, a + n / 2, a, n / 4, coins);
if (flag3) {
TwoHuaFen(a + n / 4, n / 4, coins);
OneHuaFen(a + n / 2, n / 4, coins);
} else {
TwoHuaFen(a + n / 2, n / 4, coins);
OneHuaFen(a + n / 4, n / 4, coins);
}
} else {
boolean flag23 = Cheng(a + n / 4, a + n / 2, n / 4, coins);
if (flag23) {
boolean flag3 = ChengAddVSCopy(a, a + n / 4 * 3, a + n / 4, n / 4, coins);
if (flag3) {
TwoHuaFen(a, n / 4, coins);
OneHuaFen(a + n / 4 * 3, n / 4, coins);
} else {
TwoHuaFen(a + n / 4 * 3, n / 4, coins);
OneHuaFen(a, n / 4, coins);
}
} else {
boolean flag3 = ChengAddVSCopy(a, a + n / 2, a + n / 4, n / 4, coins);
if (flag3) {
TwoHuaFen(a, n / 4, coins);
OneHuaFen(a + n / 2, n / 4, coins);
} else {
TwoHuaFen(a + n / 2, n / 4, coins);
OneHuaFen(a, n / 4, coins);
}
}
}
}
}
}
(3)n%2==0
此时我们假设n=2m,划分n为m1 m2(m默认为奇数)
首先首尾取一枚,称量
1 2 xxxxxxxxxxxxxxxxxxx n-1 n
A。平衡——真币+真币或者假币+假币此时需要继续首尾,称量
1。平衡——真币+真币或者假币+假币此时称量两次得到的两组硬币(1与2),得到的结果
a。平衡——一共取得了4枚真币,此时放回两枚后为被4整除,
重新执行m=3算法
b。不平衡——前后取出了2真2假币,此堆为二假币堆,先对下的大的一假币堆 (n-4)执行m=1算法,最后得到假币情况后,再对这个4币堆进行求二假币
2。不平衡——真币+假币,对剩下的执行m=2算法,最后处理剩下的一枚
B。不平衡——真币+假币
直接提出这两枚,剩下的进行m=2算法,最后处理这两枚。
else {//其实与n本身为奇数没有区别
boolean flag1 = Cheng(a, a + n - 1, 1, coins);
if (flag1) {//首尾平衡
boolean flag2 = Cheng(a + 1, a + n - 2, 1, coins);
if (flag2) {
boolean flag3 = Cheng(a, a + 1, 1, coins);
if (flag3) {//4枚真币//放回靠近大堆的2枚,否则死循环。
truecoin=coins.get(a);
ThreeHuaFen(a + 1, n - 2, coins);
} else {//有一次取出了两枚假币,此时有4枚需要处理
OneHuaFen(a + 2, n - 4, coins);
SpecialChuLiTwoInFour(a, a + n - 2, coins);//特殊的处理函数,有一次取的是两枚假币
}
} else {
//为了让称量次数变少,我们选择将三段link起来
List<Coin> TemCoins = new ArrayList<>();
ThreeLink(a, 1, a + 2, n - 4, a + n - 1, 1, coins, TemCoins);
TwoHuaFen(1, n - 2, TemCoins);
ThreeChuLiOneInTwo(a + 1, a + n - 2, coins);
}
} else {//首尾不平衡
TwoHuaFen(a + 1, n - 2, coins);
ThreeChuLiOneInTwo(a, a + n - 1, coins);
}
}
二、n为奇数
1 2 xxxxxxxxxxxxxxxxxxx n-1 n
首先首尾取一枚,称量
A。平衡——真币+真币或者假币+假币此时需要继续首尾,称量
1。平衡——真币+真币或者假币+假币此时称量两次得到的两组硬币(1与2),得到的结果
a。平衡——一共取得了4枚真币,此时放回一枚后为被2整除,
重新执行m=3算法
b。不平衡——前后取出了2真2假币,此堆为二假币堆,先对下的大的一假币堆 (n-4)执行m=1算法,最后得到假币情况后,再对这个4币堆进行求二假币
2。不平衡——真币+假币,对剩下的执行m=2算法,最后处理剩下的一枚
B。不平衡——真币+假币
直接提出这两枚,剩下的进行m=2算法,最后处理这两枚。
else {
boolean flag1 = Cheng(a, a + n - 1, 1, coins);
if (flag1) {//首尾平衡
boolean flag2 = Cheng(a + 1, a + n - 2, 1, coins);
if (flag2) {
boolean flag3 = Cheng(a, a + 1, 1, coins);
if (flag3) {//4枚真币//放回靠近大堆的1枚,否则死循环。
truecoin=coins.get(a);
ThreeHuaFen(a + 1, n - 3, coins);
} else {//有一次取出了两枚假币,此时有4枚需要处理
OneHuaFen(a + 2, n - 4, coins);
SpecialChuLiTwoInFour(a, a + n - 2, coins);//特殊的处理函数,有一次取的是两枚假币
}
} else {
//为了让称量次数变少,我们选择将三段link起来
List<Coin> TemCoins = new ArrayList<>();
ThreeLink(a, 1, a + 2, n - 4, a + n - 1, 1, coins, TemCoins);
TwoHuaFen(1, n - 2, TemCoins);
ThreeChuLiOneInTwo(a + 1, a + n - 2, coins);
}
} else {//首尾不平衡
TwoHuaFen(a + 1, n - 2, coins);
ThreeChuLiOneInTwo(a, a + n - 1, coins);
}
}
文件在此
通过百度网盘分享的文件:ThreeFakeCoins(1).zip
链接:https://pan.baidu.com/s/1LyuY36VbK5mB4xGJdUbkEw?pwd=2vx6
提取码:2vx6