您的位置:首页 > 产品设计 > UI/UE

5 Drease-and-Conquer Fake-Coin Problem(减治法求假币问题)

2015-07-02 23:08 966 查看

减治法Decrease and Conquer

*Exploring the relationship between a solution to a given instance of (e.g., P(n) )a problem and a solution to a smaller instance (e.g., P(n/2) or P(n-1) )of the same problem.

*Use top down(recursive) or bottom up (iterative) to solve the problem.

减治法举例Examples of Decrease and Conquer

Decrease by a constant:the size of the problem is reduced by the same constant on each iteration/recursion of the algorithm.
减去一个常量

Insertion sort

Graph search algorithms:

DFS

BFS

Algorithms for generating permutations, subsets

Decrease by a constant factor:the size of the problem is reduced by the same constant factor on each iteration/recursion of the algorithm.
减去一个常量因子

Binary search

Fake-coin problems

Variable-size decrease:the size reduction pattern varies from one iteration of an algorithm to another.
减去一个可变规模

Euclid’s algorithm

Fake-coin problems:

问题描述:

在n枚外观相同的硬币中,有一枚是假币,并且已知假币较轻。可以通过一架天平来任意比较两组硬币,从而得知两组硬币的重量是否相同,或者哪一组更轻一些,但不知道轻多少,假币问题是要求设计一个高效的算法来检测出这枚假币。

理解问题:

问题的解决是经过一系列比较和判断,可以用判定树来描述这个判定过程。

设计算法

解决这个问题的最自然的想法就是一分为二,也就是把硬币分成两组。
把n枚硬币分成两组,每组有 枚硬币,如果n为奇数,就留下一枚硬币,然后把两组硬币分别放到天平的两端。如果两组硬币的重量相同,那么留下的硬币就是假币;否则,用同样的方法对较轻的那组硬币进行同样的处理,假币一定在较轻的那组里。
考虑不是把硬币分成两组,而是分成三组,前两组有n/3 组硬币,其余的硬币作为第三组,将前两组硬币放到天平上,如果他们的重量相同,则假币一定在第三组中,用同样的方法对第三组进行处理;如果前两组的重量不同,则假币一定在较轻的那一组中,用同样的方法对较轻的那组硬币进行处理。

分析算法

1、用减治法(减半)

把n个硬币分为两堆,每堆n/2个,每次称一堆。
易见 W(1)=0

W(n)=W(n/2)+1

解得 W(n)= log2n
T(n)=O(log2n)。

2、用减治法(减n/3)

把n个硬币分为三堆,每堆n/3个,每次称任意二堆。

易见 W(1)=0

W(n)=W(n/3)+1

解得 W(n)= log3n
T(n)=O(log3n)

结果比减半法更好。

代码实现

1、减半

//求n个硬币中的一个假币

//输入:N 个硬币,假设一个假币比其它轻,

//输出:指出假币

FCR(a(n))

{

If n 是奇数,则取出一个硬币a1;

称重a1----a(n/2)和a(n/2+1)-----a(n)得weigh1 和weigh2;

If 重量相等,返回a1为假币;

Else if weigh1 >weigh2

FCR(a(n/2+1)-----a(n) );

if weigh1 < weigh2

FCR(a2----a(n/2));

}

2、减n/3

//求n个硬币中的一个假币

//输入:N 个硬币,假设一个假币比其它轻,

//输出:指出假币

#include <stdio.h>
int Coin(int a[],int low,int high,int n)
{
int num1,num2,num3,i;
int add1=0,add2=0;

if(n==1)
{
return low+1;
}

if(n%3==0)
{
num1=num2=n/3;
}

else
{
num1=num2=n/3+1;
}

num3=n-num1-num2;

for(i=0;i<num1;i++)
{
add1=add1+a[low+i];
}

for(i=num1;i<num1+num2;i++)
{
add2=add2+a[low+i];
}

if(add1<add2)
{
return Coin(a,low,low+num1-1,num1);
}

else if(add1>add2)
{
return Coin(a,low+num1-1,low+num1+num2-1,num2);
}

else
{
return Coin(a,low+num1+num2,high,num3);
}
}

int main()
{
int a[100];
int i,n,low,high,address;

printf("Please input the counts of the coins:\n");
scanf("%d",&n);

low = 0;
high = n-1;

printf("Please input the weight of every coin: \n");
for(i=0; i<n; ++i)
{
scanf("%d",&a[i]);
}

address=Coin(a,low,high,n);
printf("The fake coin is %dnd\n",address+1);

return 0;
}


拓展(纯拷贝老师的PPT):

1、不知道假币与真币相比较轻还是较重。

设有八枚硬币,分别表示为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+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的情况。



[title3]2、扩展算法,使之能处理n枚硬币中有1枚假币的问题。[/title3]

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: