问题描述:
概念
分治算法的基本思想是将一个大的复杂的问题分解成多个小的、容易解决的问题,通过解决这些小问题进而解决这个大问题。
使用分治算法需要待求解问题能够简化为若干个小规模的相同的问题,通过逐步划分,达到一个易于求解的阶段,而直接进行求解,在程序中可以使用递归方法来进行求解。
哈哈,说起来很抽象,举个例子就好理解了。
一个袋子里有n个硬币,其中一枚是假币,并且假币和真币一模一样,仅凭肉眼无法区分,仅知道假币比真币轻一些,请问如何查找到假币?
分治算法:
我们可以这样做:
将这n个硬币分成两等份,然后放到天平的两端,则假币在较轻的那一端;
然后将较轻的那一端的硬币再分成2等份,然后再放到天平的两端进行比较,假币还是在较轻的那一段;
直到最后只剩下两个硬币了,分别放到天平的两端,轻的哪一个就是假币。
当然,最后也可能剩下3个硬币,我们可以将这3个硬币中任意拿出来一个,然后将剩下的两个放到天平的两端,如果天平是平的,则说明拿出来的那个硬币就是假币;
如果天平不是平的,则轻的那一端是假币。
代码实现:
#include<iostream>
#include<cstdio>
#include<cctype>
#define MAXNUM 30
using namespace std;
int FalseCoin(int coin[], int low, int high){
int sum1, sum2, sum3;
int re;
sum1=sum2=sum3=0;
if(low+1==high){
if(coin[low]<coin[high]){
re=low+1;
return re;
}
else{
re=high+1;
return re;
}
}
if((high-low+1)%2==0){
for(int i=low; i<=low+(high-low)/2; i++){
sum1=sum1+coin[i];
}
for(int i=low+(high-low)/2+1; i<=high; i++){
sum2=sum2+coin[i];
}
if(sum1>sum2){
re=FalseCoin(coin, low+(high-low)/2+1, high);
return re;
}
else if(sum1<sum2){
re=FalseCoin(coin, low, low+(high-low)/2);
return re;
}
else{
}
}
else{
for(int i=low; i<=low+(high-low)/2-1; i++){
sum1=sum1+coin[i];
}
for(int i=low+(high-low)/2+1; i<=high; i++){
sum2=sum2+coin[i];
}
sum3=coin[low+(high-low)/2];
if(sum1>sum2){
re=FalseCoin(coin, low+(high-low)/2+1, high);
return re;
}
else{
}
if(sum1+sum3==sum2+sum3){
re=low+(high-low)/2+1;
return re;
}
}
}
int main(){
int coin[MAXNUM];
int i,n;
int locate;
cout<<"分治算法求解假硬币问题!\n";
cout<<"请输入硬币总数目: ";
cin>>n;
cout<<"请输入硬币的真假:";
for(i=0; i<n; i++){
cin>>coin[i];
}
locate=FalseCoin(coin, 0, n-1);
cout<<"在上述"<<n<<" 个硬币中,第"<<locate<<"个硬币是假的!"<<endl;
return 0;
}
执行结果: