伯努利装错信封问题

题目描述

    某人写了n封信,同时为每一封信写1个信封,共n个信封。如果把所有的信都装错了信封,问共有多少种?(这是组合数学中有名的错位问题。著名数学家伯努利(Bernoulli)曾最先考虑此题。后来,欧拉对此题产生了兴趣,称此题是“组合理论的一个妙题”,独立地解出了此题)
    试编程求出完全装错情形的所有方式及其总量s。例如,输入n=3,即有3封信需要装入信封,完全装错的一种方式可以表示为312,表示第1封信装入第3个信封,第2封信装入第1个信封,第3封信装入第2个信封。对于n=3,完全装错的方式共有2种,分别是312和231.

输入

输入一个正整数n(2<=n<=6)

输出

输出完全装错情形的所有方式以及装错方式的总量s (每行输出5种方式,一行中的相邻两种方式之间用1个空格隔开。装错方式输出时,从小到大排列,见输出样例)。

样例输入

4

样例输出

2143 2341 2413 3142 3412
3421 4123 4312 4321
s=9

思路

1,每个信封从信1开始放,直到放到信6,输出符合的摆法

2,如果当前信封不符合则返回上一个信封,改变信封里的信

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

仅看代码可能还是难理解,这里以输入3举例

i=1
a[1]=2
        第一次循环                              第十次循环
i=2                                i=3
a[2]=1                             a[3]=2
        第二次循环                              第十次循环
i=3                                i=1
a[3]=1                             a[1]=3
        第三次循环                              第十一次循环
i=3                                i=2
a[3]=2                             a[2]=1
        第四次循环                              第十二次循环
i=3                                i=3
a[3]=3                             a[3]=1   
        第五次循环                              第十三次循环
i=2                                i=3
a[3]=4                             a[3]=2
        第六次循环                              第十四次循环
i=2                                a[1]=3,a[2]=1,a[3]=2输出312
a[2]=2
        第七次循环
i=2
a[2]=3
        第八次循环
i=3
a[3]=1
        第九次循环
a[1]=2,a[2]=3,a[3]=1  输出231                 
                

 
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jchenn

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

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

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

打赏作者

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

抵扣说明:

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

余额充值