题目描述
输出自然数1到n所有不重复的排列,即n的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

我们可以模拟出n个盒子和n张卡片,我们需要将n张卡片分别放到n个盒子里,且每个盒子只能放1张卡片,那有多少种方案呢?

我们来模拟一下放卡片。

现在放了第1张卡片,接下来亦是如此。

产生排列"1 2 3"。

经过综上,已经完成了一种排列。那是不是就结束了呢?显然不是!因为产生了一种排列后需要立即返回,现在我们要把第3张卡片收回。

取回了第3张卡片后,发现手里仍然只有第3张卡片,没有别的选择,于是不得不把2号卡片收回。

现在手里有2张卡片了,分别是2、3号卡片。现在需要把3号卡片放入第2个盒子里,放好后再把2号卡片放到3号盒子里,产生排列"1 3 2"。

接下来按照上面的程序去模拟,会依次生成所有排列"2 1 3"、"2 3 1"、"3 1 2"、"3 2 1"。

这个模拟的过程,就是dfs的基本操作。

现在请出代码。

考虑2个情况:1是如何往盒子里放卡片,2是放过的卡片就不能放到其他盒子里了,因为一个盒子只能放1个卡片。这里1个for循环和标记判断就能搞定。

for(i=;i<=n;i++)//从1到n个盒子产生排列
{
if(b[i]==)//如果卡片在手上,b[i]==0表示第i号卡片在手上
{
a[step]=i;//将第i个卡片放入第step个盒子里
b[i]=;//标记第i号卡片不在手上
}
}

这里a数组是表示小盒子,b数组是标记卡片是否在手上。step表示正处在第step个盒子上。

OK,现在已经处理掉第step个盒子了,接下来往深处走,处理第step+1个盒子。如何处理step+1个盒子呢?其实和处理第step个盒子是一样的。显然我们需要把刚才处理第step个盒子封装成函数。

inline void dfs(int step)//处理第step个盒子
{
for(i=;i<=n;i++)//从1到n个盒子产生排列
{
if(b[i]==)//如果卡片在手上,b[i]==0表示第i号卡片在手上
{
a[step]=i;//将第i个卡片放入第step个盒子里
b[i]=;//标记第i号卡片不在手上
}
}
return;
}

好,写成函数就好办了,在处理完第step个盒子后,就要处理第step+1个盒子,方法就是dfs(step+1)。

inline void dfs(int step)//处理第step个盒子
{
for(i=;i<=n;i++)//从1到n个盒子产生排列
{
if(b[i]==)//如果卡片在手上,b[i]==0表示第i号卡片在手上
{
a[step]=i;//将第i个卡片放入第step个盒子里
b[i]=;//标记第i号卡片不在手上
dfs(step+);//通过递归实现处理下一个盒子
b[i]=;//一定要把刚才尝试的卡片收回,才能进行下一次尝试
}
}
return;
}

上面b[i]=0十分重要,因为在一次摆放尝试结束返回时,如果不把刚才的卡片收回,那将无法进行下一次摆放。

还有一个问题,什么时候才能输出一个满足要求的序列呢?我们再回到那张模拟图。

由图可知,当满足条件时应该就是卡片全部都在盒子里。当我们要处理第n+1个盒子时,说明前n个盒子都已经放好卡片了。

inline void dfs(int step)//处理第step个盒子
{
if(step==n+)//如果前面n个盒子已经排列好
{
for(i=;i<=n;i++)//输出
{
cout<<a[i]<<' ';
}
cout<<endl;
return;//非常重要!返回之前一步,也就是最近调用一次dfs的地方,否则程序将无止境地调用下去
}
for(i=;i<=n;i++)//从1到n个盒子产生排列
{
if(b[i]==)//如果卡片在手上,b[i]==0表示第i号卡片在手上
{
a[step]=i;//将第i个卡片放入第step个盒子里
b[i]=;//标记第i号卡片不在手上
dfs(step+);//通过递归实现处理下一个盒子
b[i]=;//一定要把刚才尝试的卡片收回,才能进行下一次尝试
}
}
return;
}

完整代码如下:

#include <stdio.h>
#include <iostream>
using namespace std;
int a[],b[],n;
void print()
{
int i;
for(i=;i<=n;i++)
{
cout<<a[i]<<' ';
}
cout<<endl;
}
inline void dfs(int i)//现在是第i层,也可以看成是第i个盒子,把数据放到这个盒子里
{
int j;
if(i==n+)//如果到达了第n+1层说明已经搜索完成,输出
{
print();//输出方案
return;//返回上一层(上一个盒子)
}
for(j=;j<=n;j++)//开始放数据
{
if(b[j]==)//这个数可以放(未标记)
{
a[i]=j;//放这个数
b[j]=;//标记被放过了
dfs(i+);//放第i+1个盒子(层)
b[j]=;//返回之前一步,回溯
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;
dfs();//开始深搜
return ;
}

通过一个例子我们发现,dfs也就那回事。还是开头那句话:理解深搜的重要关键点是在于解决“现在该怎么做”。至于“接下来该怎么做”和“现在该怎么做”是一样的(这在骗分中十分重要)。比如上述程序的dfs(step)就是当你在第step个盒子前你应该怎么做。通常应该用循环把每一种可能都试一遍,当这步解决后就处理下一步[dfs(step+1)]。

下面是dfs的模版。

inline void dfs(int step)
{
判断边界
开始尝试每一种可能
{
...
dfs(step+);//继续下一步
}
return;//返回
}

DFS 之 全排列的更多相关文章

  1. DFS实现全排列

    复习一下DFS实现全排列,具体思想见:https://www.cnblogs.com/chiweiming/p/9279858.html public class Main{ static int a ...

  2. (DFS、全排列)POJ-2718 Smallest Difference

    题目地址 简要题意: 给若干组数字,每组数据是递增的在0--9之间的数,且每组数的个数不确定.对于每组数,输出由这些数组成的两个数的差的绝对值最小是多少(每个数出现且只出现一次). 思路分析: 对于n ...

  3. 用DFS 解决全排列问题的思想详解

    首先考虑一道奥数题目: □□□ + □□□ = □□□,要将数字1~9分别填入9个□中,使得等式成立.例如173+286 = 459.请输出所有合理的组合的个数. 我们或许可以枚举每一位上所有的数,然 ...

  4. C++DFS方法全排列

    前几天看纪磊的<啊哈!算法>一书,里面讲算法讲的特别通俗细致,真的是初中生都能读得懂的算法书(我大二才读:P).这段代码很适合初学算法的同学. #include<iostream&g ...

  5. dfs 的全排列

    #include <iostream> #include <algorithm> #include <cstdio> #include <string> ...

  6. (DFS、全排列)POJ-3187 Backward Digit Sums

    题目地址 简要题意: 输入两个数n和m,分别表示给你1--n这些整数,将他们按一定顺序摆成一行,按照杨辉三角的计算方式进行求和,求使他们求到最后时结果等于m的排列中字典序最小的一种. 思路分析: 不难 ...

  7. DFS输出全排列

    前言 输入n(1 <= n <= 20),按字典序输出所有1~n的排列.如果排列数量太多,则只需要输出前100个 输入样例 3 输出样例 1 2 3 1 3 2 2 1 3 2 3 1 3 ...

  8. 洛谷 P1706 全排列问题 :STL / dfs

    题目描述 输出自然数1到n所有不重复的排列,即n的全排列,要求所产生的任一数字序列中不允许出现重复的数字. 输入输出格式 输入格式: n(1≤n≤9) 输出格式: 由1-n组成的所有不重复的数字序列, ...

  9. DFS+模拟 ZOJ 3861 Valid Pattern Lock

    题目传送门 /* 题意:手机划屏解锁,一笔连通所有数字,输出所有可能的路径: DFS:全排列 + ok () 判断函数,去除一些不可能连通的点:) */ #include <cstdio> ...

随机推荐

  1. #学号 20175201张驰 《Java程序设计》第1周学习总结

    教材学习内容总结 第一章 ·第一章的内容相对简单,我并未遇到大的困难. ·1.Java特点:语法简单.面向对象.与平台无关.动态. ·2.关于编写源文件:源文件名字必须与public类的名字相同:保存 ...

  2. 用git如何把单个文件回退到某一版本

    暂定此文件为a.jsp 1.首先到a.jsp所在目录: 通过 git  log a.jsp 查看a.jsp的更改记录 2.找到想要回退的版本号:例如 fcd2093 通过 git reset  fcd ...

  3. SystemParametersInfo调置壁纸、屏幕保护程序

    应用SystemParametersInfo函数可以获取和设置数量众多的windows系统参数.这个小程序就是运用了SystemParametersInfo函数来设置桌面的墙纸,而且程序可以让我们选择 ...

  4. POJ 3080 Blue Jeans(Java暴力)

    Blue Jeans [题目链接]Blue Jeans [题目类型]Java暴力 &题意: 就是求k个长度为60的字符串的最长连续公共子串,2<=k<=10 规定: 1. 最长公共 ...

  5. hive sql执行的job在map时报java.lang.OutOfMemoryError的错误

    较为详细且重要的一段报错信息是org.apache.hadoop.mapred.YarnChild: Error running child : java.lang.OutOfMemoryError: ...

  6. Centos7 Firewall 防火墙配置应用实例参考(转)

    时间:2016-06-02 02:40来源:linux.it.net.cn 作者:IT   简单的配置,参考学习:--permanent  当设定永久状态时 在命令开头或者结尾处加入此参数,否则重载或 ...

  7. 【python】python2.x中的除法

    在生信分析中有许多时候我们需要用到除法,在经历无数次break out 之后我终于发现原来python 2.x中只有整除,而没有浮点除法,这就是没有基础的弊病. 那么如何在python 2.x中运用除 ...

  8. 2015全国大学生数学建模B题浅谈

    题目请自主上网获取. 分析下思路.第一问,不同时空的出租车的“供求匹配”程度. 也就是说要选取的数据要有时间和地理两个维度.实体对象是出租车.关键的问题就是地点怎么选? 选择的城市具备如下经济较发达, ...

  9. STATS 326 Applied Time Series

    STATS 326Applied Time SeriesASSIGNMENT THREEDue: 2 May 2019, 11.00 am(Worth 6% of your final grade)H ...

  10. Bugku-CTF之flag在index里

      Day15 flag在index里 http://123.206.87.240:8005/post/