n枚硬币问题(找假币)

问题描述:

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

解题思路:

    使用减治法的解题思路,将硬币分为3堆,则每堆的硬币数量为 n/3 ,但是这是在 n%3==0 的情况下才能成立,所以我们将 n 枚硬币分为 3 堆加 1 堆 余数堆(余数堆可能为0),则可分为如下(n-n%3)/3,  (n-n%3)/3,  (n-n%3)/3,    n%3.

如下图:

(n-n%3)/3

(n-n%3)/3

(n-n%3)/3

n%3

a

b

c

d

  1. 首先获取真币,通过随机数组中取三枚硬币,互相比较,相等的两枚为真币,任意取一枚作为真币 记录 数组下标。
  2. 首先判断n中的硬币数量,如果n>2则执行2,否则执行5.
  3. 将n分为上图的四堆,拿 a 和 b 比较,如果 a == b ,则 假币在 c 或 d 中。否则假币在 a 或 b 中。
  4. 如果 a == b,则拿 a 和 c 比较。如果 a == c,则假币在d中。将 d 再次 执行本流程。如果不等,则假币在 c 中,将 d (余数堆) 再次 执行流程,并且n=n%3,。
  5. 如果 a != b,则拿 a 和 c 比较。如果 a == c,则假币在b中。将 b 再次 执行本流程。如果不等,则假币在 a 中,将 a 再次 执行流程  2,并且n=(n-n%3)/3。
  6. 如果n==2,则将两枚硬币与真的硬币(通过 数组下标 )进行比较,不同的为假币,输出结果,结束。
  7. 如果n==1,则该硬币就是假币,输出结果结束。

  *注:按照2-5流程分堆下去,在最后一执行流程 2 时,n中含有假币,并且n只可能为1或2.(初始时,n>3,若n<3,则不能判断真假)

主要代码如下:

 1 //计算硬币总重量
 2  int sum_coin(int coin[],int m,int n){
 3      int result=0;
 4      if(m>n)
 5          return 0;
 6      for(int i=m;i<=n;i++){
 7          result+=coin[i];
 8      }
 9
10      return result;
11  };
12
13
14  //找出假币   m , n 数组下标,coin 硬币数组,relCoin 真币数组下标
15  int check_coin(int coin[],int m,int n,int& relCoin){
16
17         int vary=n-m+1;
18
19         int restCoin=vary%3;
20         int vary2=vary-restCoin;
21
22         if(vary==1)
23             return m;
24
25         if(vary==2)
26         {
27             if(sum_coin(coin,m,m)==sum_coin(coin,relCoin,relCoin))
28                 return n;
29             else
30                 return m;
31
32         }
33
34
35         if(sum_coin(coin,m,m+vary2/3-1)==sum_coin(coin,m+vary2/3,m+(vary2/3)*2-1))//第一堆 == 第二堆
36         {
37             if( (sum_coin(coin,m,m+vary2/3-1)==sum_coin(coin,m+(vary2/3)*2,m+vary2-1)))//第一堆 == 第三堆
38                 check_coin(coin,n-restCoin+1,n,relCoin);
39             else//第一堆 != 第三堆
40                 check_coin(coin,m+(vary2/3)*2,m+vary2-1,relCoin);
41         }
42         else//第一堆 != 第二堆
43         {
44             if(sum_coin(coin,m,m+vary2/3-1)==sum_coin(coin,m+(vary2/3)*2,m+vary2-1))//第一堆 == 第三堆
45                 check_coin(coin,m+vary2/3,m+(vary2/3)*2-1,relCoin);
46             else//第一堆 != 第三堆
47                 check_coin(coin,m,m+vary2/3-1,relCoin);
48         }
49
50  };
51
52
53  //返回真币数组下标
54  int getRelCoin(int coin[],int m,int n)
55  {
56      if(n-m+1<=2)
57      {
58          cout<<"硬币数小于3枚!!!无解";
59         return -1;
60      }
61      else
62      {
63          if(coin[0]==coin[1])
64          {
65              return 0;
66          }
67          else
68          {
69              if(coin[0]==coin[2])
70                  return 2;
71              else
72              {
73                  return 1;
74              }
75          }
76      }
77
78  };
时间: 2024-12-14 19:12:50

n枚硬币问题(找假币)的相关文章

算法设计与分析 ------最近对问题与8枚硬币问题

利用减治法实现8枚硬币问题: 参考资料:http://blog.csdn.net/wwj_748/article/details/8863503    算法设计--八枚硬币问题 1 #include "stdafx.h" 2 #include <iostream> 3 #include <stdio.h> 4 using namespace std; 5 6 7 void eightcoin(int arr[]); 8 void compare(int a,in

xth的第 12 枚硬币(codevs 1366)

题目描述 Description 传说 xth 曾经拥有11枚完全相同硬币(你懂得),不过今年呢,rabbit又送了他一 枚硬币.这枚硬币和其他硬币外观相同,只有重量不同,或轻或重.Xth 一不小心, 将这枚特殊的硬币和其他硬币混在了一起.Rabbit 知道后很生气,要他立刻把那枚 硬币找出来,并且还要说出这枚硬币是轻还是重.可怜的 Xth 只有一架普通托盘天 平,并且只能称量三次(每次称量,两边各四枚).现在全部 12枚硬币编号为 A~L,现给出你三次称量的结果,请你帮 xth 找出那枚不一样

找假币

就是输入一堆硬币的个数,输出最快的情况下最少几次能搞定? 这是一个能通过的解答: // write your code here cpp #include <iostream> using namespace std; //分三次称,每次分配使天平一边的硬币数大于剩余没称的硬币数, //因此称1次后,最多再需要称的次数等于在天平一边的硬币数中找出假币需要称的次数 //可是为什么称三次最快呢? int func(int num) { if(num == 1) return 0; else if(

一枚硬币

今天上公交车的时候,掏钱包时一枚1角的硬币从钱包里掉出滚到了车的中间,因为是上车人多,我就没有弯下腰去拣,当时心想也就是1角硬币没什么,但当我入座后,发现前排的几位老人都撇了我一眼.我这才会想起刚才的一幕.也觉得自己确实做错了什么.不是一角钱的问题,而是 1. 1角钱虽然不多,但买东西时少了一角钱,你就是理亏的(对别人也是不公平的) 2. 你不去拣他可能就没有人去拣了,这1角钱可能永远都发挥不了它的价值了(变成铁矿石不算) 3. 你不重视1角钱,可能你会失去更多的钱,自己珍惜的东西才不容易丢.

硬币找零问题的动态规划实现

一,问题描述 给定一组硬币数,找出一组最少的硬币数,来找换零钱N. 比如,可用来找零的硬币为: 1.3.4   待找的钱数为 6.用两个面值为3的硬币找零,最少硬币数为2.而不是 4,1,1 因此,总结下该问题的特征:①硬币可重复多次使用.②在某些情况下,该问题可用贪心算法求解.具体可参考:某种 找换硬币问题的贪心算法的正确性证明 二,动态规划分析 为了更好的分析,先对该问题进行具体的定义:将用来找零的硬币的面值存储在一个数组中.如下: coinsValues[i] 表示第 i 枚硬币的面值.比

POJ1013称硬币【枚举】

Counterfeit Dollar Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 52474   Accepted: 16402 Description Sally Jones has a dozen Voyageur silver dollars. However, only eleven of the coins are true silver dollars; one coin is counterfeit ev

有趣的天平秤假币问题

问题描述: 有12枚硬币,其中有一枚是假币,但是不知道是重还是轻.现给定一架没有砝码的天枰,问至少需要多少次称量才能找到这枚硬币?如何证明给出的方案是最少次数? 思路分析: 我们首先想到的可能是将12枚硬币分成两堆,每堆6枚放到天枰上称量,这样的得到的结果一定是天枰是倾斜的.得不到任何其他信息,反而白白浪费了一次称量机会.因此第一次称量一定是选择一部分去称量,利用均分原理,天枰左边放一部分硬币,右边放一部分硬币,还剩下一部分硬币.从平均情况考虑,三部分中含有假币的概率是相等的.因此,第一次称量中

c语言进阶10-算法

一.  数据结构和算法关系 为什么要学数据结构和算法? 通常,计算机解决问题的步骤如下: 在数学模型中,计算机处理的对象之间通常存在着一种最简单的线性关系,这类数学模型就是线性的数据结构.著名计算机科学家沃斯(Nikiklaus Wirth)提出一个公式:程序=数据结构+算法.数据结构就是编程的思维,编程的灵魂,算法的精髓所在,没有了数据结构,程序就好像一个空核,是低效率的.算法与数据结构是紧密联系不可分割,必须在一起才能最终解决问题.算法是程序设计的的灵魂. 二.  两种算法的比较 在此之前大

Java-POJ1013-Counterfeit Dollar

在13枚硬币中找出fake的那一个 输入:三次天平称量结果 1 package poj.ProblemSet; 2 3 import java.util.Scanner; 4 5 /* 6 我怎么觉得是贪心算法呢? 7 起初对所有硬币标记0: 8 如果是even,则两边所有的硬币记为真(记233): 9 否则就对不确定的硬币记录怀疑(++或者--根据天平倾斜方向): 10 最后只要看哪个硬币的绝对值最大,也就是被怀疑的次数最多,即是假币. 11 */ 12 public class poj101