算法学习——回溯之伯努利装错信封问题
算法描述
某人给6个朋友每个人都写了一封信,同时写了这6个朋友地址的信封,有多少种投放信笺的方法,使得每封信与信封上的收信人都不相符?
算法思路
-
6封信可能出现的结果:
-
所有的信都是在对应的信封中,也就是所有的信都放对了信封,这种情况只有一种
-
部分信放错了信封
-
全部信都放错了信封
-
-
题目要求的就是求最后一种情况,也就是全部新都放错了信封
-
定义一个数组
a[i]
,a[1] = 1
表示第一封信放在了第一个信封中 -
限制条件
-
a[i]!=i
即限制信放在正确的信封中 -
a[i]!=a[j]
即限制信不能放在同一个信封
-
-
回溯条件
a[i]=6
即已经遍历到了最后一封信
算法实现
System.out.println("输入n:");
Scanner scaner = new Scanner(System.in);
int n = scaner.nextInt();
scaner.close();
int s = 0;//解的个数统计
int[] a = new int[n+1];
a[1]=2;
int i=1;
while(true){
boolean flag = true;
if(a[i]!=i){
for(int j=1;j<i;j++){
if(a[j]==a[i]){
flag = false;
break;
}
}
}else{
flag = false;
}
if(flag&&i==n){
s++;
for(int j=1;j<=n;j++){
System.out.print(a[j]);
}
System.out.print(" ");
//出现十个解换行
if(s%10==0){
System.out.println("");
}
}
if(flag&&i<n){
i++;
a[i]=1;
continue;
}
while(a[i]==n&&i>0){
i--;//回溯,a[i]到末尾,则回溯
}
if(i>0){
a[i]++;//向后移
}else{
break;
}
}
System.out.println("\n"+"s="+s);