2021-10-21伯努利装错信封问题的个人解析 引用了Jchenn的代码(因为我也是看了别人的代码才会了这道题 )

#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;
}

 对于此代码,一开始再用纸笔运行的时候,在while循环漏了情况,之后的几次运行也是一样,直到用电脑调试了一次,才发现。

这道题有几个点:

1.因为第一个数不能放在第一位,那么这个数从最小开始(最小是这个题的一个关键),第一位放2。

2.最小对于这段代码,可以发现下一个信封放的位置总是从1开始判断,如果直到最后一个信封都没有信封可以放这封信,那前面的信放的就有点问题了,要返回到前面的信封,并且前面的信封要加1(为什么要加?因为此代码的判断机制是从最小的数开始,一个一个判断相比较规定和前面的信,看放在这个位置是否合法,意思就是该位置前面的都为不合法,所以只要往后加就行了)

3.当一个数结束了,怎么做到往下继续呢?代码从最小开始,再往下走就比如一开始输入的数是四

,那么第一个数应该是2143吧,那么这个数已经判断合法了,我们对其继续加1,那么组合数便是2144,如此累加带来的结果便是高位数往上走,而当最高位也到4时候并且flag=0,那么就退出循环了,还是举一开始输入4的例子吧 最后一个数4321那么a[4]=1,这是按照判断a[4]=2,然后是a[4]=3,再到a[4]=4,然后是a[3]=3,然后是a[3]=4,然后是a[2]=4,接着还是while循环,这个时候a[1]也是4,i--,i=0;退出循环了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值