DFS入门引导之全排列问题

DFS:优先考虑深度,简单地讲就是一条路走到尽头,撞了南墙,无路可走的情况下,才选择回头,重新选择一条路。

题目:假设有编号为1,2,3的三张牌和编号为1,2,3的三个盒子。把3张牌分别放入3个盒子一共有几种不同的放法?(输入一个数n,输出n的全排列)

解题思路:假如现在我手里有三张牌,最开始我走到第1号盒子面前,把1号牌放进去;然后我走到第2号盒子面前,把2号牌放进去;之后又继续向前一步,走到3号盒子面前,把3号牌放进去。这样完成了一种排列,我再向前走一步,已经到尽头了,所以我又要回头(前面的那个return),重新选择一种方法。可是我现在手里已经没有牌了,所以我要把3号盒子里的3号牌拿出来,但是我现在手上还是只有一张牌,我面前也只有一个盒子,所以我继续往后退一步(后面的那个return),走到2号盒子面前,同样拿回2号牌,然后把3号牌放到2号盒子里,往前走一步,走到3号盒子面前,把剩下的2号牌放到3号盒子里

代码思路:定义一个a数组,作为盒子,step为我当前走到了哪个盒子面前,a[step]表示我现在走到了第step号盒子面前;定义一个book数组,用作我是否把牌放完了的标记,放完了手中的那张牌标记为1,还在手中则标记为0。

代码展示:

#include <stdio.h>
int n,step;//step表示当前在第几个盒子面前
int a[10],book[10];//a数组表示盒子的移动,输出a[i]表示这个盒子里装的数;book数组用来标记这个数有没有被放掉(放掉为1)
void dfs(int step)//当前站在第step个盒子面前
{
	int i,j;//i不能定义为全局变量,因为全局作用域为整个程序,而局部为当前函数或循环
	if(step==n+1)//如果走到最后一个盒子并且放完了
	{
		for(j=1;j<=n;j++)//输出盒子里放的数
			printf("%d",a[j]);
		printf("\n");
		return;//返回到之前被调用的地方(上一级),若当前为dfs(3)则返回到dfs(2)返回到"dfs(step+1)"处,
	}			//并且拿起之前的那张牌(重新标记为0),开始另一种放法,即"book[i]=0"

	//这部分必须在for循环的前面,不然每次i都重新赋值1了
	for(i=1;i<=n;i++)//手中的1 2 3张牌
	{
		//printf("前for(i):%d\n",i);
		if(book[i]!=1)//如果这张牌没有被放掉,就放到我面前的这个盒子里,并且标记为1
		{	//printf("前if(i):%d\n",i);			//没有被放掉,才能执行“dfs(step+1)”(走到下一步),如果被放掉了,
			a[step]=i;	//就i++,看下一张牌,如果i>n了,所有的牌都放掉了,就"return",再退回到上一个盒子
			book[i]=1;
			dfs(step+1);//放完手中的牌,走到下一个盒子,通过调用自己判断是否走到最后一个盒子并放完了,
				book[i]=0;						//(if(step==n+1)不成立)如果没有则重做for循环i又从1开始(继续放手中剩下的牌)
				//printf("后if(i):%d\n",i);		//(if(step==n+1)成立)如果走到最后一个盒子了(return调回来的),再退回到这一个盒子,
		}													//则把上个盒子里的牌拿回手中“book[i]=0”
		//printf("后for(i):%d\n",i);
	}
	//printf("for外(i):%d\n",i);
	return;//for结束了,无路可走了,或者这种放牌方法已经完成,就退到上一步(上个盒子的位置)
}
int main()
{
	scanf("%d",&n);
	dfs(1);//从第一个盒子开始放
	return 0;
}

代码理解:进入dfs(step),当前step为1,if(step==n+1)不成立,执行for循环,此时i=1,if成立,a[1]=1,book[1]=1;dfs(2),if(step==n+1)不成立,执行for循环,此时i=1,if不成立,执行i++,i=2,if成立,a[2]=2,book[2]=1;dfs(3),if(step==n+1)不成立,执行for循环,此时i=1,if不成立,执行i++,i=2,if不成立,执行i++,i=3,if成立,a[3]=3,book[3]=1;dfs(4),if(step==n+1)成立,输出1 2 3之后return回溯到dfs(3),执行book[3]=0,(还在for循环内),执行i++,i=4,退出for,执行for外的return,回溯到dfs(2),执行book[2]=0,(还在for循环内),执行i++,i=3,if成立,a[2]=3,book[3]=1;dfs(3),if(step==n+1)不成立,执行for循环,此时i=1,if不成立,执行i++,i=2,if成立,a[3]=2,book[2]=1;dfs(4),if(step==n+1)成立,输出1 3 2之后return回溯到dfs(3),book[3]=0,i++,i=4,退出for,执行return回溯到dfs(2),执行book[2]=0,i++,i=3,if不成立,i++,i=4,退出for循环;return回溯到dfs(1),执行book[1]=0,i++,i=2,if成立,a[1]=2,book[2]=1,dfs(2),if(step==n+1)不成立,执行for循环,此时i=1,if成立,a[2]=1,book[1]=1,dfs(3),if(step==n+1)不成立,执行for循环,此时i=1,if不成立,执行i++,i=2,if不成立,i++,i=3,if成立,a[3]=3,book[3]=1,dfs(4),if(step==n+1)成立,输出2 1 3.........

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LUSAIQUN637

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值