# 算法 ## 算法思想 ### 穷举算法思想 穷举算法(ExhaustiveAttackmethod)是最简单的一种算法,其依赖于计算机的强大计算能力来穷尽每一种可能的情况,从而达到求解问题的目的。穷举算法效率并不高,但是适应于一些没有明显规律可循的场合。 #### 基本算法思想 穷举算法的基本思想就是从所有可能的情况中搜索正确的答案,其执行步骤如下: 1. 对于一种可能的情况,计算其结果。 2. 判断结果是否满足要求,如果不满足则执行第(1 ) 步来搜索下一个可能的情况;如果满足要求,则表示寻找到一个正确的答案。 > 注意:在使用穷举算法时,需要明确问题的答案的范围,这样才可以在指定范围内搜索答案。指定范围之后,就可以使用循环语句和条件判断语句逐步验证候选答案的正确性,从而得到需要的正确答案。 #### 经典例子 《孙子算经》【鸡兔同笼问题】 今有鸡兔同笼,上有三十五头,下有九十四足,问鸡兔各几何? (在一个笼子里关着若干只鸡和若干只兔,从上面数共有 35 个头;从下面数共有 94 只脚。问笼中鸡和兔的数量各是多少?) ``` int chickenRabbit(int head,int foot,int *c,int r){ int i,j; int tag=0;//标志是否有解 for(i=0;i<=head;i++){//鸡的个数穷举 j=head-i;//兔子的个数 if(i2+j*4==foot){//判断是否满足条件 tag=1; *c=i; *r=j; } } return tag; } int main() { int c,r; if(chickenRabbit(35,94,&c,&r)==1){//如果有解输出 printf("chickens=%d,rabbits=%d\n",c,r); }else{//如果无解 printf("无解\n"); } return 0; } ``` ### 递推算法思想 递推算法是非常常用的算法思想,在数学计算等场合有着广泛的应用。递推算法适合有明显公式规律的场合。 #### 基本算法思想 递推算法是一种理性思维模式的代表,根据已有的数据和关系,逐步推导而得到结果。递推算法的执行过程如下: (1) 根据已知结果和关系,求解中间结果。 (2)判定是否达到要求,如果没有达到,则继续根据已知结果和关系求解中间结果。如果满足要求,则表示寻找到一个正确的答案。 【注意】递推算法需要用户知道答案和问题之间的逻辑关系。在许多数学问题中,都有明确的计算公式可以遵循,因此可以采用递推算法来实现。 #### 经典例子 斐波那契《算盘书》【兔子产仔问题】 如果一对两个月大的兔子以后每一个月都可以生一对小兔子,而一对新生的兔子出生两个月后才可以生小兔子。也就是说,1 月份出生,3 月份才可产仔。那么假定一年内没有产生兔子死亡事件,那 么 1 年后共有多少对兔子呢? 【规律分析】 第一个月:a(1)=1 对兔子; 第二个月:a(2)=1 对兔子; 第三个月:a(3)=1+1=2 对兔子; 第四个月:a(4)=1+2=3 对兔子; 第五个月:a(5)=2+3=5 对兔子; …… 第 n 个月:a(n)=a(n-1)+a(n-2)对兔子; ``` int Fibonacci(int n) { int tl,t2; if (n==1||n==2)//第1、2个月都只有1对兔子 { return 1; }else{//采用递归 tl=Fibonacci(n-1); t2=Fibonacci(n-2); return tl+t2;//计算第n个月的兔子对数 } } int main() { int n=12; printf("%d个月后兔子对数:%d\n",n,Fibonacci(n)); return 0; } ``` ### 递归算法思想 递归算法是非常常用的算法思想。使用递归算法,往往可以简化代码编写,提高程序的可读性。但是,不合适的递归会导致程序的执行效率变低。 #### 基本算法思想 递归算法就是在程序中不断反复调用自身来达到求解问题的方法。这里的重点是调用自身,这就要求待求解的问题能够分解为相同问题的一个子问题。这样 ,通过多次递归调用,便可以完成求解。 递归调用是一个函数在它的函数体内调用它自身的函数调用方式,这种函数也称为“递归函数”。在递归函数中,主调函数又是被调函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层。 函数的递归调用分两种情况:直接递归和间接递归。 • 直接递归:即在函数中调用函数本身。 • 间接递归:即间接地调用一个函数,如出如 func_a 调 用 func_b, func_b 又调用 func_a。间接递归用得不多。 【注意】编写递归函数时,必须使用 if 语句强制函数在未执行递归调用前返回。否则,在调用函数后,它永远不会返回,这是一个很容易犯的错误。 #### 经典例子 【阶乘】 ``` n!=n(n-1)(n-2)……21 1 long fact(int n){ if(n<=1)return 1; else return nfact(n-1); } int main() { int n=11; printf("%d的阶乘是%d\n",n,fact(n)); return 0; } ``` ### 分治算法思想 分治算法是一种化繁为简的算法思想。分治算法往往应用于计算步骤比较复杂的问题,通过将问题简化而逐步得到结果。 #### 基本算法思想 分治算法的基本思想是将一个计算复杂的问题分为规模较小,计算简单的小问题求解,然后综合各个小问题,得到最终问题的答案。分治算法的执行过程如下: (1)对于一个规模为 N 的问题,若该问题可以容易地解决(比如说规模>^较小),则直接解决,否则执行下面的步骤。 (2)将该问题分解为” 个规模较小的子问题,这些子问题互相独立,并且原问题形式相同。 (3)递归地解子问题。 (4)然后,将各子问题的解合并得到原问题的解。 【注意】使用分治算法需要待求解问题能够化简为若干个小规模的相同问题,通过逐步划分,达到一个易于求解的阶段而直接进行求解。然后,程序中可以使用递归算法来进行求解。 #### 经典例子 【寻找假币问题】 一个袋子里有 30 个硬币,其中一枚是假币,并且假币和真币一模- 样,肉眼很难分辨,目前只知道假币比真币重量轻一点。请问如何区分出假币? ``` int falseCoin(int coin[],int low,int high){ int i,sum1,sum2,sum3; int re; sum1=sum2=sum3=0; //若只有两个硬币 if(low+1==high){ if(coin[low]sum2){//后半段轻,假币在后半段 re=falseCoin(coin,low+(high-low)/2+1,high); return re; }else if(sum1sum2){//后半段轻,假币在后半段 re=falseCoin(coin,low+(high-low)/2+1,high); return re; }else if(sum1