#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;退出循环了