(Java实现) HDOJ 2068 RPG的错排 错排及组合

时间:2022-08-24 11:26:56

问题: 十本不同的书放在书架上。现重新摆放,使每本书都不在原来放的位置。有几种摆法?
这个问题推广一下,就是错排问题,是组合数学中的问题之一。考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。 n个元素的错排数记为D(n)。 研究一个排列错排个数的问题,叫做错排问题或称为更列问题。

1.错排问题的解释

      当n个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用D(n)表示,那么D(n-1)就表示n-1个编号元素放在n-1个编号位置,各不对应的方法数,其它类推.

第一步,把第n个元素放在一个位置,比如位置k,一共有n-1种方法(如下图,把1号小球放在3号位置);
(Java实现) HDOJ 2068 RPG的错排 错排及组合
第二步,放编号为k的元素,这时有两种情况:
(1)把它放到位置n,那么,对于剩下的n-1个元素,由于第k个元素放到了位置n,剩下n-2个元素就有D(n-2)种方法;
  (把被占的3号位置所对应的3号小球放置在1号位置,相当于2个位置已被预订,去除这两个位置后,原问题缩小为n-2规模的   问题,即有D(n-2)种方法
(Java实现) HDOJ 2068 RPG的错排 错排及组合
(2)第k个元素不把它放到位置n,这时,对于这n-1个元素,有D(n-1)种方法;
  (若不把3号小球放置在1号位置,对于这未放置的n-1个小球和n-1个位置,原问题缩小为n-1规模的问题,即有D(n-1)种方法
综上得到
D(n) = (n-1) [D(n-2) + D(n-1)]
     Java代码实现:

	//错排的公式
	private static void wrongsort() {
		a[0] = 0;
		a[1] = 0;
		a[2] = 1;
		for(int i = 3; i < n; i++){
			a[i] = (i - 1) * (a[i-1] + a[i-2]);
		}
		
	}

2.问题描述

今年暑假杭电ACM集训队第一次组成女生队,其中有一队叫RPG,但做为集训队成员之一的野骆驼竟然不知道RPG三个人具体是谁谁。RPG给他机会让他猜猜,第一次猜:R是公主,P是草儿,G是月野兔;第二次猜:R是草儿,P是月野兔,G是公主;第三次猜:R是草儿,P是公主,G是月野兔;......可怜的野骆驼第六次终于把RPG分清楚了。由于RPG的带动,做ACM的女生越来越多,我们的野骆驼想都知道她们,可现在有N多人,他要猜的次数可就多了,为了不为难野骆驼,女生们只要求他答对一半或以上就算过关,请问有多少组答案能使他顺利过关。
 
Input
输入的数据里有多个case,每个case包括一个n,代表有几个女生,(n<=25), n = 0输入结束。
     

3.解题思路

       题目要求排列对一半或以上,问题可转化为:假设总女生数n中有m个位置排错了(m<n/2),即为m个元素的错排与这m个元素的组合之积(给排错的女生排在不同错误的位置的机会)。

1)计算出错排的答案数;
2)计算出对应排错女生数量的不同组合总数;
3)重复步骤1~2,依次算出少于一半人数下的组合错排方案数。

Java实现代码:

import java.util.Scanner;

public class Main {
	static int[] a = new int[14];

	public static void main(String[] args) {
		wrongsort();
		Scanner in = new Scanner(System.in);
		while(in.hasNextInt()){
			int n = in.nextInt();
			if(n == 0){
				break;
			}
			
			long sum = 1;
			for(int i = 2; i <= n/2; i++){
				sum += C(n,i) * a[i];
			}
			
			System.out.println(sum);
		}

	}

	//组合数
	private static double C(int n, int m) {
		double s = 1;
		for(int i = 0; i < m; i++){
			s = s * (n - i) / (i + 1);
		}
		return s;
	}

	//错排
	private static void wrongsort() {
		a[0] = 0;
		a[1] = 0;
		a[2] = 1;
		for(int i = 3; i < 14; i++){
			a[i] = (i - 1) * (a[i-1] + a[i-2]);
		}
		
	}

}
(更多解题代码及解释在 git


参考资料:

1. 错排公式_百度百科