回溯法——伯努利装错信封问题

回溯法——伯努利装错信封问题

问题描述

某人给6个朋友每人写了一封信,同时写了这6个朋友地址的信封,有多少种投放信笺的方法,使每封信与信封上的收信人都不相符?

程序设计(C)

#include <stdio.h>
int main()
{
	int n,i,j,t,a[30];
	long s=0;
	printf("请输入整数n(2<n<10):");
	scanf("%d",&n);
	i=1;  //第i封信
	a[i]=2;  //第i封信在第几个信封
	while(1)
	{
	    t=1;  //判断,满足条件为1,不满足为0
	    if(a[i]!=i)  //第i封信不在第i个信封
	    {
	      for(j=1;j<i;j++)  //循环,与前面放好的信做比对
	        if(a[j]==a[i])  //第i封信和第j封信在同一个信封,不满足条件
	        {
	          t=0;
	          break;
	        }
	    }
	    else t=0;  //第i封信在第i个信封,不满足条件
	    if(t&&i==n)  //已经到最后一封信了,前面的信也都可以放到满足条件的位上了
	    {
	      for(j=1;j<=n;j++)  //所有条件均满足,输出
	        printf("%d",a[j]);
	      printf("   ");  //输出一个解后,加空格
	      if(++s%10==0)  //s计算解的个数,每输出10个解,换行
	        printf("\n");
	    }
	    if(t&&i<n)  //前面的信放到满足条件的位上了,且还没到最后一封信
	    {
	      i++;
	      a[i]=1;
	      continue;  //放 下一封信,从第一个信封开始试
	    }
	    while(a[i]==n&&i>0)  //第i封信已经试到最后一个信封了,且i>0
	      i--;  //调整或回溯,调整前面的信
	    if(i>0)  a[i]++;   //把第i封信位置前移
	    else break;  //前面没有信可以调位置了,break
	  }
	printf("\n%d个整数全错位排列共以上%ld个。\n",n,s);
	return 0;
}

程序运行结果

在这里插入图片描述

ps:
在学习回溯法时,花了好久好久才明白程序的写法,清楚每一步的意思。所以,在这里对大部分代码进行了说明,希望可以让还在回溯法中迷路的小伙伴们能弄懂一些。可能有些地方的描述还不是很完善,唔,可以先去了解了解 皇后问题 的解法,再来理解这个可能会更清楚一些,它们是类似的。

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值