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