定义:
1 2 3 4的错排有
4 3 2 1,4 1 2 3,4 3 1 2,
3 4 1 2,3 4 2 1,2 4 1 3,
2 1 4 3,3 1 4 2,2 3 4 1。
第一列是4分别与1,2,3互换位置,其余两个元素错排.由此生成的。
第2列是4分别与3,1,2(123的一个错排)的每一个数互换而得到的。即
4 1 2 3,3 4 2 1 ,3 1 4 2
第三列则是由另一个错排231和4换位而得到,即
4 3 1 2, 2 4 3 1 ,2 3 4 1
设n个数1,2,…,n错排的数目为Dn, 任取其中一数i,
n-2个数进行错排,共得(n-1)Dn-2个错排。另一部分为数i以外的n-1个数进行错排,然后i与其中每个数互换,得(n-1)Dn-1个错排。
综合以上分析结果得递推关系
Dn=(n-1)(Dn-1+Dn-2),
以上是一个网站上给出的解答,但是我一直在想这是怎么解决重复问题呢?也就是说怎么才能保证这样的递推是没有重复的。现在我想通了,我们可以这样理解,对第n个数,如果是n-1个数原本符合要求,那么第n个数和前n-1个数都交换一次即可,这是一种情况。也可以是在前n-1个数中有一个数不是错排的,即对i数的排列还是在第i个位置上,这时只要把i和n交换也满足了条件,这是第二种情况。这样来理解就方便多了!
这类型的题的应用也是很广泛的,如:N个人从一个箱子中抽取自己的名字,如果抽取到了,就是胜利者,这个时候没有胜利者的情况有多少种;还有就是N个新郎去找自己的新娘,问有M对找错的情况是多少;等等,这些都是错排问题,n个人错排的情况是多少就是上面的公式:f(n) = (n-1)(f(n-1)+f(n-2));
- import java.io.BufferedInputStream;
- import java.math.BigInteger;
- import java.util.Scanner;
- public class Main {
- /**
- * @param args
- */
- public static void main(String[] args) {
- Scanner scan=new Scanner(new BufferedInputStream(System.in));
- BigInteger[] ans=new BigInteger[1005];
- ans[1]=BigInteger.ZERO;
- ans[2]=BigInteger.ONE;
- ans[3]=BigInteger.valueOf(2);
- for(int i=4;i<=1000;i++){
- ans[i]=(ans[i-1].add(ans[i-2])).multiply(BigInteger.valueOf(i-1));
- }
- int t=0;
- while(true){
- int n=scan.nextInt();
- if(n==0)
- break;
- t++;
- System.out.println("Case"+" "+t+":");
- System.out.println(ans[n]);
- }
- }
- }