分治算法思想解决找假硬币的问题

来源:互联网 发布:php soap header 验证 编辑:程序博客网 时间:2024/06/08 17:01

概念

分治算法的基本思想是将一个大的复杂的问题分解成多个小的、容易解决的问题,通过解决这些小问题进而解决这个大问题。

使用分治算法需要待求解问题能够简化为若干个小规模的相同的问题,通过逐步划分,达到一个易于求解的阶段,而直接进行求解,在程序中可以使用递归方法来进行求解。

哈哈,说起来很抽象,举个例子就好理解了。

一个袋子里有n个硬币,其中一枚是假币,并且假币和真币一模一样,仅凭肉眼无法区分,仅知道假币比真币轻一些,请问如何查找到假币?

分治算法:

我们可以这样做:

将这n个硬币分成两等份,然后放到天平的两端,则假币在较轻的那一端;

然后将较轻的那一端的硬币再分成2等份,然后再放到天平的两端进行比较,假币还是在较轻的那一段;

直到最后只剩下两个硬币了,分别放到天平的两端,轻的哪一个就是假币。


当然,最后也可能剩下3个硬币,我们可以将这3个硬币中任意拿出来一个,然后将剩下的两个放到天平的两端,如果天平是平的,则说明拿出来的那个硬币就是假币;

如果天平不是平的,则轻的那一端是假币。


C++语言程序代码:

#include<iostream>using namespace std;/**************定义查找硬币的函数find_false()**********************/int find_false(int a[],int low,int high){int i=0;//作为遍历的计数器 int re=0;//re作为返回值int sum1,sum2,sum3;//三个用来累加的变量sum1=sum2=sum3=0;if(low+1==high)//当遍历到最后两个元素的时候 {if(a[low]<a[high]){re=low;return re;}else{re=high;return re;}} if((high-low+1)%2==0)//当长度为偶数的时候{for(i=low;i<=low+(high-low+1)/2-1;i++)//对前半段求和 {sum1+=a[i];}for(i=low+(high-low+1)/2;i<=high;i++)//对后半段求和 {sum2+=a[i];}if(sum1<sum2)//假币在前半段 {re=find_false(a,low,low+(high-low+1)/2-1);return re;}else if(sum2<sum1)//假币在后半段 {re=find_false(a,low+(high-low+1)/2,high);return re;}}else//当长度为奇数的时候 {for(i=low;i<=low+(high-low)/2-1;i++)//对前半段求和{sum1+=a[i];}for(i=low+(high-low)/2+1;i<=high;i++)//对后半段求和{sum2+=a[i];}sum3=a[low+(high-low)/2];//sum3用于存放中间数据 if(sum1<sum2)//假币在前半段 {re=find_false(a,low,low+(high-low)/2-1);return re; }else if(sum2>sum1){re=find_false(a,low+(high-low)/2,high);return re;}else if(sum1+sum3==sum2+sum3)//中间的那个就是假币!{re=(high-low)/2+1;return re;} } } int main(){int a[100];int n,i,re;cout<<"请输入硬币的个数:";cin>>n;cout<<"请分别输入这个"<<n<<"个硬币的重量:"<<endl;for(i=1;i<=n;i++){cin>>a[i];}re=find_false(a,1,n);cout<<"假币是第"<<re<<"硬币"<<endl;return 0;}

程序运行结果: