DFS的理解,从排列到组合
来源:互联网 发布:淘宝收货地址 编辑:程序博客网 时间:2024/05/16 11:56
全排列问题
- 全排列问题
输入数组{1,2,3}的全排列,我们将这个问题形象化。
假设手里有编号1,2,3的三个扑克牌,和1,2,3的三个盒子。需要将三个扑克牌分别放入这个三个盒子当中,并且每个盒子只有一个扑克牌可以放
首先来到一号盒子旁边,每一个都要放一编。约定一个顺序,到一个盒子面前,都先放1号,再放2号,最后放3号。在一号盒子里面放了编号1,来到二号只能放入编号2,3,按照约定只能放入编号2,于是三号盒子只能放入编号3.当到了第四个盒子的时候,发现没有第四个盒子,将前面数字1,2,3记录下来输出,这就是一个全排列。但是没有结束,此时需要回到3号盒子前,将三号盒子的编号3取出,但是手中没有别的编号的牌,所以只能退到二号箱中取出二号箱子的东西。然后手中有2,3两个编号,可以向二号箱子中放入3号牌,然后三号箱子中放入2号牌,此时又产生一个新的排列。
这个就是全排列的思路。首先解决怎么向小盒子中放入扑克牌,这里用一个for循环解决
for(i=1; i <= n; i++){ a[step] = i;//将第i个扑克牌放入第step个箱子中}
如果一个扑克牌只能放入一个盒子中,那么就将同样的扑克牌放入别的盒子中,因为已经没有这个小盒子了。所以需要用一个数组book来标记哪些牌已经使用过了。
for(i = 1; i <=n; i++){ if(book[i] == 0) //表示扑克牌依旧在手上 { a[step] = i; book[i] = 1; //扑克牌已经不在手上了 }}
处理完第step个·盒子了,接下来还要往前走一步,继续处理第step+1个小盒子,那么如何处理,和处理第step个盒子是一样的,因此将刚才的步骤封装成一个函数
void dfs(int step){ //step表示现在在第几个盒子面前 for(i=1; i <= n; i++){ if(book[i] == 0){ //表示i号扑克牌仍然在手上 a[step]=i; //放入在step盒子中 book[i] = 1; //表示已经放过 } }}
处理完第step个盒子,去处理step+1个盒子
void dfs(int step){ for(int i = 1; i <= n; i++){ a[step] = i; book[i] = 1; dfs(step+1); book[i] = 0; }}
最后把结束条件加上
void dfs(int step)//step表示现在站在第几个盒子面前 { int i; if(step == n+1)//如果站在第n+1个盒子面前,则表示前n个盒子已经放好了扑克牌 { //输出一种排列 for(i=1;i<=n;i++) put(a[i]); return;//返回之前的一步(最近一次调用dfs函数的地方) } //站在第step个盒子的面前,按照1、2、3...n的顺序一一尝试 for(i = 1; i <= n; i++) { if(book[i] == 0)//表示i号扑克牌仍然在手上 { a[step]= i;//将i号扑克牌放入到第step个盒子中 book[i] = 1;//表示i号扑克牌已经不在手上了 dfs(step+1); book[i] = 0; } } }
上面的步骤就是dfs的应用,理解深度优先搜索的关键在于解决“当下该如何做”。至于“下一步如何做”则与“当下该如何做”是一样的。比如我们这里写的dfs(step)函数的主要功能就是解决当你在用step个盒子的时候你该怎么办。通常的方法就是把每一种可能都去尝试一遍(一般用for循环遍历)。当前这一步解决后便进入下一步dfs(step+1)。下一步的解决方法和当前这一步的解决方法是完全一样的。下面的代码就是深度优先搜索的基本模型。
void dfs(int step){ 判断边界 尝试每一种可能(){ 继续下一步dfs(n+1); }}
从n个数中取k个排列的问题
上面已经解决了全排列的问题,就是盒子数和排数相等,现在我们解决非全排列的问题。在这里k是小于等于n的,这个说明每个盒子放上了牌或者没有放上牌。
```void dfs(int step)//step表示现在站在第几个盒子面前 { int i; if(step == k+1)//如果站在第k+1个盒子面前,则表示前n个盒子已经放好了扑克牌 { //输出一种排列 for(i=1;i<=n;i++) put(a[i]); return;//返回之前的一步(最近一次调用dfs函数的地方) } //站在第step个盒子的面前,按照1、2、3...n的顺序一一尝试 for(i = 1; i <= n; i++) { if(book[i] == 0)//表示i号扑克牌仍然在手上 { a[step]= i;//将i号扑克牌放入到第step个盒子中 book[i] = 1;//表示i号扑克牌已经不在手上了 dfs(step+1); book[i] = 0; } } } <div class="se-preview-section-delimiter"></div>
组合问题
组合问题和排列问题最大的区别就是:组合没有顺序,排列有顺序,123 和 132在组合中是同一种组合,但是在排列中确是不同的排列。假设有5个牌需要放到三个盒子中去。假设一号箱子里面已经有了一号牌,二号箱子里面已经有了二号牌,顺序是123,124,125的情况已经全部尝试过了,就不能考虑一号箱子是1号牌而其他箱子有2号牌出现的情况了。如同123和132
1-2-x的所有情况我们都考虑完后,我们就可以在排除2的情况下考虑所有1-3-x的情况。然后是1-4-x,但会出现1-5-x吗?不会啦~因为一共只有5张牌哦~而所有的牌此时都被标记为已用哦,即book为1,所以第三个箱子里是没有可以放的牌的!程序会直接跳过滴,我们就不用担心啦。此时带有1的所有组合我们都考虑完毕啦,于是给它对应的book标记上1。于是我们顺利退回到一号箱子,在一号箱子中放入了2号牌,接下来在不考虑1号的情况下排列出2-x-x的组合。思路已经和上面完全一样啦!我们将会得到234、235和245。得到的最后一个组合就是345了。
void dfs(int step){ int i; if(step == k+1){ //输出一种组合 for(i = i; i <= k; i++){ put(a[i]); } return;//返回最近一次调用dfs的地方 } //站在第step个盒子的前面,按照1,2,3...n的顺序一一尝试 for(int i = 1; i <= n; i++){ if(book[i] == 0) //表示扑克牌仍然在手上 { a[step] = b[i]; //第i个扑克牌中吵架 book[i] = 1;//表示i个扑克牌已经不在受伤了 dfs(step+1); book[i] = 0;//收回手中的牌 if(flag == 1){ book[i] = 1; flag = 0; } } if(i == n) //表示在某个箱子已经遍历完成了从1到n号的所有扑克牌 flag = 1; } return;}<div class="se-preview-section-delimiter"></div>
这样就造成了一个问题:比如说在6选4的组合中,得到1234、1235、1236后,3号牌被标记成了1后,就不会再得到1345、1346、1356这三个组合。所以我们需要将部分数字恢复成可用状态。我们用一个for循环消除从当前牌号的下一位到最后一张牌的标记,以便以后再次使用。
void dfs(int step)//step表示现在站在第几个盒子面前 { int i; if(step == k+1)//如果站在第k+1个盒子面前,则表示前k个盒子已经放好了扑克牌 { //输出一种排列 for(i=1;i<=k;i++)//注意这里只输出 puts(a[i]); return;//返回之前的一步(最近一次调用dfs函数的地方) } //站在第step个盒子的面前,按照1、2、3...n的顺序一一尝试 for(i = 1; i <= n; i++) { if(book[i] == 0)//表示i号扑克牌仍然在手上 { a[step]= b[i];//第i个扑克牌放入到第step个盒子中 book[i] = 1;//表示i号扑克牌已经不在手上了 dfs(step+1);//走到下一个小盒子面前 book[i] = 0;//收回盒子中的牌 if(flag == 1) { book[i] = 1; flag = 0; for(int j=i+1; j<=n; j++)//消除从当前牌号的下一位到最后一张牌的标记,以便以后再次使用 book[j] = 0; } } if(i == n)//表示在第step个箱子上已经遍历完了从1到n号的所有扑克牌 flag = 1; } return; } int main() { for(int i=1; i<=n; i++) b[i] = i; dfs(1);//首先站在1号小盒子面前 return 0; }
转载:http://blog.csdn.net/yyyds/article/details/51712604
- DFS的理解,从排列到组合
- 从排列与组合的python实现到"生日问题"的解释
- dfs 生成排列和组合
- DFS搜索排列与组合
- 从排列到组合——深度优先搜索
- NYOJ-32组合数(数的全排列,简单dfs)
- hdu 1716 排列2 dfs 组合
- 用dfs实现1到n的全排列
- 字符串的排列/组合
- 字符串的排列、组合
- 字符串的组合排列
- 所有组合, 所有排列的模板(从n个数中选m个数的所有组合和所有排列)
- 数组中任意n个数的全排列(DFS)以及任意n个数的组合
- n个里面选m个元素的所有排列+组合dfs
- 组合数,5,3从大到小排列
- 从0到n的排列的一种求法
- 字符串的组合排列(非全排列)
- collectionView的流布局实现从左面到右面排列
- spring main测试
- 【java】jdk1.5新特性详解
- 图灵测试——与Emacs Doctor对话
- 朴素贝叶斯
- 机器学习实验——安装Octave
- DFS的理解,从排列到组合
- 纯html/css练手项目-电商网站
- 配置Unity VR开发环境
- 欢迎使用CSDN-markdown编辑器
- 2789: [Poi2012]Letters
- 特征选择与稀疏学习
- 从零开始学贪心算法
- es6特性实践
- Linux Kernel 调度实现 -----欣赏