递归思想—全排列

        大家高中数据额应该学过全排列吧?比如给大家1,2,3三个数,全排列共有123,132,213,231,312,321,即A32=6,共6种全排列方式。

        如果使用for循环,可以用如下代码实现操作:

int i,j,k;
for(i=1;i<=3;i++)
    for(j=1;j<=3;j++)
        for(k=1;k<=3;k++)
            if(i!=j && i!=k && j!=k)
                printf("%d%d%d",i,j,k);

        代码看起来简单明了很容易实现,不就是三层for循环嘛?但是如果是1,2,3,4四个数全排列呢?你会说,那就写四层for循环呗,这还不简单?但是如果是n个数进行全排列呢,难道要写n层for循环吗?这样做显然是耗费时间和精力的。

   

例题引入:熊大,熊二,熊泉清三个人要过生日了,小牛准备了3份生日礼物,分别标记为礼物1,礼物2,礼物3。每只熊只能领到一份生日礼物,但是领到礼物几就不一定了,需要小牛手动分发。小牛想知道,共有几种分发礼物的方法?

        这时候,小牛先走到熊大面前,但是犹豫是给礼物1呢,还是给礼物2呢,还是给礼物3呢?似乎给礼物几都可以,既然如此,小牛心想:走到一只熊面前,都按照礼物序号从小到大分发。

        根据这个决规定,小牛把礼物1给了熊大,此时手里还有礼物2礼物3,分别分给了熊二和熊泉清。然后此时不需要再考虑有没有其他人需要礼物了,因为礼物只准备了3份。此时有排列为“礼物1 礼物2 礼物3”。

        是不是只有这一种分法呢?显然不是,这时候,小牛重新回到熊泉清面前,尝试看看能不能不给熊泉清礼物3,把礼物3拿回来然后给熊泉清其他序号的礼物,结果小牛发现,自己手里只有礼物3了,没有更好办法的情况下,小牛只能去拿回熊二手里的礼物2,现在小牛手里有两份礼物了,分别是礼物2和礼物3,按照之前的约定,这次把礼物3给熊二,把礼物2给熊泉清。此时产生了新的排列“ 礼物1 礼物3 礼物2”。

        按照以上的步骤,便会产生6种分发礼物的方法,那么如何用代码实现呢?我如何知道,几号礼物在自己手里,几号礼物已经分发出去了呢?此时,我们只需用一个for循环就可以解决问题。

        

for(i=1;i<=n;i++){//n是礼物的个数
    if(book[i]==0){//book[i]=0时表明礼物i还在手中,没有被分出去
        a[step] = i;
        book[i] = 1;
    }
    //这里数组表示需要领取礼物的熊的数量
    //a[step]表示当前在第step个熊面前
    //a[step] = i 表示第礼物i分给了第几只熊
    //同时,我们需要记录礼物几已经被分发出去不在小牛手中了
}

如果用函数把以上代码封装起来,就是:

void digui(int step){
    for(i=1;i<=n;i++){
        if(book[i] == 0){    //book[i]==0表示第i号礼物仍在自己手上
            a[step] = i;    //将第i号礼物给第step个熊
            book[i] = 1;    //book[i]设为1,表示第i号礼物不在手中
        }  
    }
}

写好以后,就很好办了,我们只需要分好第step只熊的礼物后,接着分发第step+1只熊的礼物即可,分发第step+1只熊的礼物的办法就是digui(step+1)

void digui(int step){
    for(i=1;i<=n;i++){
        if(book[i] == 0){    //book[i]==0表示第i号礼物仍在自己手上
            a[step] = i;    //将第i号礼物给第step个熊
            book[i] = 1;    //book[i]设为1,表示第i号礼物不在手中
            dfs(step+1);    //这里是通过函数的递归调用实现(自己调用自己)
            book[i] = 0;    //一定要把分好的礼物再收回,才能进行下一步分发
        }  
    }
}

同时,我们需要判断是否已经把礼物全部分发完毕,总不能没有礼物了,还继续分发对叭!,所以我们需要增加判断语句,进行判断,当全分发完毕后,输出分发的结果。

完整代码如下:

#include<stdio.h>
int a[10],book[10],n;
int dg(int step){//step表示现在在给第几个熊分发礼物 
	int i;
	if(step == n+1){
	//此时理论上应该给第n+1只熊分发礼物,也证明前n只熊都得到了礼物 
		for(i=1;i<=n;i++)
			printf("%d",a[i]);
		printf("\n");
		return ;
	}
	for(i=1;i<=n;i++){
		if(book[i]==0){
			a[step] = i;
			book[i] = 1;
			dg(step+1);
			book[i] = 0;
		} 
	}
	return ;
} 
int main(){
	scanf("%d",&n);//n为1-9的整数
	dg(1);//首先先给1号熊分发礼物 
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值