《算法问题实战策略》-chaper7-穷举法

关于这一章节《算法实战策略》有一段概述问题,我认为对于编程人员来说非常有价值,故在这里进行如下的摘抄:

构想算法是很艰难的工作。相比大家都经历过,面对复杂的要求只是傻乎乎地盯着显示器,或者不经过深思熟虑就开始打键盘,结果还要辛辛苦苦修改变得一塌糊涂的代码。经过这些磨难,各位就能切身体会到设计算法的重要性。

与通常所想不同,支配设计算法的并不是一时的灵感,而是许多策略性的选择。构想算法不仅需要理解问题的特性,还要理解执行时间和占用内存空间之间的对立关系,而且要会选择适当的数据结构。

算法设计范式指的是,算法为解决给定问题而采用的策略或观点。有些算法会共享出解决问题时最重要的领会,将之积累起来就会领悟到一种模式。从这个意义上说,这些领会是通过相同策略或相同范式解决问题的。

算法设计范式可作为设计算法的框架,因此,学习这些范式将有助于提高算法设计的能力。

——摘自《算法实战策略》

关于穷举法,可以说是计算机领域最为人熟知但却有大大忽略的一种基础算法了。很多人都会知道,它的思想就是将解空间给一一列举出来然后进行计数或者其他的什么操作。有较好算法基础的人会知道,搜索(DFS、BFS)本质上也是一种穷举,只不过他们针对不同类型的问题所设计出来的基于递归和搜索树结构的穷举方法,这里其实已经开始体现出穷举法解决问题的灵活性,并非很多人印象中那么简单。而利用穷举策略解决问题的时候,还将会面临下面几个大问题:

(1)    穷举过程中重复情况的计算:即我们要设计的穷举过程一定要“有序”,所谓“有序”就是要做到“不重不漏”的一一列举出所有情况。

(2)    穷举过程复杂度的分析:在具体的解题中我们往往会遇到穷举时时间、空间溢出的情况,这时候我们需要做的就是优化,映射到上文提及到的搜索其实就是剪枝策略。

那么下面我们结合这两个方面,通过具体的问题来实战体会这种范式设计思维。

Q:给出学生数n(n≤10)和他们之间的朋友关系,现在进行两两配对,请问有多少种不同的配对方法?

分析:

首先我们思考这道问题会有哪些重复计数的坑,能够看到,我们进行一组配对,比如(1,2)所形成的二元对视无序的,即(1,2)和(2,1)是一样的,对此我们在编程设计中,进行“配对”的时候就不能够设计两层循环了,而是通过规定二元对(a,b)中b>a来排除这些重复情况。

其次是对穷举过程复杂度的分析,基于个问题数据n的最大值,我们能够看到至多穷举的情况数是9*7*5*3*1 = 945,计算机处理起来是绰绰有余的因此不需要考虑优化。

另外要说的一个层面的问题是,在设计穷举的时候,如果说一种情况要分成多个决策过程,那么此时最好的方法就是基于递归和搜索树的深搜策略,它更加强调各种情况生成时的联系,而如果各种情况相对独立的话,那么进行简单的暴力枚举即可。

这道题目的函数代码如下:

 int n;

bool areFriend[10][10];

int countPairings(bool taken[10])//标记配对情况的数组

{

    int  firstFree = -1;

    for(int i = 0;i < n;i++)//找到当前bool表中第一个没有配对的人

    {

          if(!taken[i])

          {

               firstFree = i;

               break;

          }

    }

    if(firstFree == -1)  return 1;   //所有人已完成配对,得到一种配对方法,返回1

    int ret = 0;

    for(int pairWith = first +1;pairWith < n;++pairWith)

    {

         if(!taken[pairWith] && areFriend[firstFree][pairWith])

         {

            taken[firstFree] = true;

            taken[pairWith]  = true;

            ret += countPairings(taken);

            taken[firstFree] = false;

            taken[pairWith]  = false;   

         }

    }

    return ret;

}

//由于数据较小,为了处理的方便,对于n<10的情况,我们可以将缺少的人记为已经配对,而在areFriend[][]需要初始化为0;而这一步骤在上面的部分代码中并没有体现,

//读者在完成完成代码的时候需要注意补充。
时间: 2024-09-30 20:38:57

《算法问题实战策略》-chaper7-穷举法的相关文章

1-5、算法设计常用思想之穷举法

穷举法又称穷举搜索法,是一种在问题域的解空间中对所有可能的解穷举搜索,并根据条件选择最优解的方法的总称.数学上也把穷举法称为枚举法,就是在一个由有限个元素构成的集合中,把所有元素一一枚举研究的方法. 使用穷举法解决问题,基本上就是以下两个步骤: • 确定问题的解(或状态)的定义.解空间的范围以及正确解的判定条件: • 根据解空间的特点来选择搜索策略,逐个检验解空间中的候选解是否正确: 解空间的定义解空间就是全部可能的候选解的一个约束范围,确定问题的解就在这个约束范围内,将搜索策略应用到这个约束范

算法问题------爬梯子问题 穷举法 递归法 动态规划 简单循环

http://home.juedui100.com/user/24086697.htmlhttp://home.juedui100.com/user/24081650.htmlhttp://home.juedui100.com/user/24050915.htmlhttp://home.juedui100.com/user/24083352.htmlhttp://home.juedui100.com/user/24061195.htmlhttp://home.juedui100.com/user

算法基础一 穷举法

/*穷举法*/ /*鸡兔同笼35头,94足,鸡兔各几只?*/ #include<stdio.h> const int Num = 35; const int Foots = 94; int main() { int cN;//鸡 int rN;//兔 for (cN = 0; cN <= 35; cN++) { rN = Num - cN; if (Foots == cN * 2 + rN * 4 ) { printf("鸡:%d,兔:%d\n",cN,rN); }

C#跳转语句 迭代法 穷举法

一.跳转语句 break & continue break:跳出循环,终止此循环,不管下面还有多少次,全部跳过. string a=" ", for (int i=1;i<=10;I++) { if(i==5) { break; } a += i +",": } Console.WriteLine(a); 输出结果为 1,2,3,4,5 continue:终止此次循环,直接开始下次循环. string a=" ", for (int

什么叫穷举法?

穷举法的基本思想是根据题目的部分条件确定答案的大致范围,并在此范围内对所有可能的情况逐一验证,直到全部情况验证完毕.若某个情况验证符合题目的全部条件,则为本问题的一个解:若全部情况验证后都不符合题目的全部条件,则本题无解.穷举法也称为枚举法. 用穷举法解题时,就是按照某种方式列举问题答案的过程.针对问题的数据类型而言,常用的列举方法一有如下三种: (1)顺序列举 是指答案范围内的各种情况很容易与自然数对应甚至就是自然数,可以按自然数的变化顺序去列举. (2)排列列举 有时答案的数据形式是一组数的

XTU OJ 1175 Hurry Up(三分法&amp;&amp;穷举法)

 Hurry Up Accepted : 88   Submit : 345 Time Limit : 1000 MS   Memory Limit : 65536 KB Problem Description GG is some what afraid of his MM. Once his MM asks, he will always try his best to rush to their home. Obvious, he can run home in straight li

穷举法解决旅行商问题

一.问题描述 如图所示,一个旅行商从A点出发,需要不重复地走遍5个城市ABCDE,最后回到A.每个城市之间的花费(即权值)如图所示,现在要求找出一条总花费最小的路径,即权值和为最小的路径. 二.     算法说明 1.    算法一: 登山法(贪心法) 即在每一个城市出发前比较接下来所能走的城市花费(权值),找出权值最小的走. 优缺点:由于只是在每个城市局部地考虑权值最小,但当走完所用城市后,所得到权值和不一定为最小,所以采用此算法得不到精确解,但此算法复杂度较低. 2.  算法二:穷举法(本程

15-07-03 语句- for () 循环语句-穷举法

for()  穷举法 用循环把各种可能的情况都走一遍,然后用if条件把满足要求的结果给筛选出来. 例如:1.找100以内的偶数 for (int i = 0; i <= 100; i++) { if (i % 2 == 0) { Console.WriteLine(i); } } 2.小明单位发了50元的购物卡,他到超市买洗化用品,一是牙刷(5元),二是香皂(2元),三是牙膏(10元)怎么可以正好把五十元花完. for (int ys = 0; ys <= 10; ys++) { for (i

for循环的应用:迭代法和穷举法

for()循环.四要素:初始条件,循环条件,状态改变,循环体.执行过程:初始条件--循环条件--循环体--状态改变--循环条件....注意:for的小括号里面分号隔开,for的小括号后不要加分号.for的嵌套.应用:迭代法,穷举法.一.迭代法:有一定规律. 每次循环都是从上次运算结果中获得数据,本次运算的结果都是要为下次运算做准备. 二.穷举法:用循环把各种可能的情况都给走一遍,然后用if条件把满足要求的结果给筛选出来.