`
dyccsxg
  • 浏览: 205311 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
社区版块
存档分类

计算组合数并输出

    博客分类:
  • Java
阅读更多

问题描述:计算一组数据的组合数并输出

 例如:输入1,2,3,4,5时,大小取3,共有C(5,3)=10个组合数,
 将其从小到大依次排序可分组如下:
 ----
 123 
 124
 125
 134
 135
 145
 ----
 234
 235
 245
 ----
 345
 解题思路:求长度为 n 的source[]数组,且大小为 m 的第 x 个组合数
 1)获取组合数的第一个字符
   因为 C(n,m) = C(n-1,m-1) + C(n-2,m-1) + .. + C(m-1,m-1)
   所以可依次计算 C(n-k,m-1) [1 <= k <= n-m+1]的值,直到
   x < C(n-1,m-1) + C(n-2,m-1) + .. + C(n-k,m-1)
   这时 source[k-1] 就是组合数的第一个字符
 2)获取下一个字符
   在获取了第一个字符之后,记 
   y = x - (C(n-1,m-1) + C(n-2,m-1) + .. + C(n-k+1,m-1))
   问题降级为在起始下标为 k,长度为 n-k 的source[]数组中,
   选择大小为 --m 的第 y 个组合数,因此可重复1)的过程
 3)当 m == 1时,选取组合数的最后一个字符,完成运算
   

 

package org.demo.algorithm;
/**
 * 计算并输出组合数
 * @author  
 * @date    2010-9-13
 * @file    org.demo.algorithm.Combination.java
 */
public class Combination {
	/**
	 * 测试
	 * @param args
	 */
	public static void main(String[] args) {
		String[] source = {"1","2","3","4","5","6"};
		int m = 3;
		int size = (int)getCnm(source.length,m);
		for (int i=0; i<size; i++){
			String data = getValue(source,m,i);
			System.out.println("[" + i + "] " + data);
		}
	}
	/**
	 * 计算数组 source[] 中大小为 m 的第 x 个组合数
	 * 按下述原理分组
	 * C(n,m) = C(n-1,m-1) + C(n-1,m)
	 * C(n,m) = C(n-1,m-1) + C(n-2,m-1) + C(n-2,m)
	 * ...
	 * C(n,m) = C(n-1,m-1) + C(n-2,m-1) + .. + C(m,m-1) + C(m,m)
	 * C(n,m) = C(n-1,m-1) + C(n-2,m-1) + .. + C(m,m-1) + C(m-1,m-1)
	 * 最后一步转换是因为 C(m,m) == C(m-1,m-1)
	 * @param source
	 * @param m 组合数的大小,且 1 <= m <= source.length
	 * @param x [0,C(n,m))
	 * @return
	 */
	public static String getValue(String[] source,int m,int x){
		// 数组大小
		int n = source.length;
		// 存储组合数
		StringBuilder sb = new StringBuilder();
		int start = 0;
		while(m > 0){
			if (m == 1){
				// m == 1 时为组合数的最后一个字符
				sb.append(source[start + x]);
				break;
			}
			for (int i=0; i<=n-m; i++){						
				int cnm =  (int)getCnm(n-1-i,m-1);
				if(x <= cnm-1){
					sb.append(source[start + i]);
					// 启始下标前移
					start = start + (i + 1);
					// 搜索区域减小
					n = n - (i+1);
					// 组合数的剩余字符个数减少
					m--;
					break;
				} else {
					x = x - cnm;					
				}		
			}
		}
		return sb.toString();
	}
	/**
	 * 计算组合数
	 * 计算组合数的推导过程如下,
	 * 因为直接计算 n! 容易发生数据溢出,故可改为计算 ln(n)
	 * C(n,m) = n!/(m!(n-m)!) 
	 * C(n,m) = n(n-1)..(n-m+1)/m!
	 * ln(C(n,m)) = ln(n(n-1)..(n-m+1)/m!)
	 * ln(C(n,m)) = ln(n(n-1)..(n-m+1)) - ln(m!)
	 * ln(C(n,m)) = (ln(n) + ln(n-1) + .. + ln(n-m+1))
	 *             -(ln(m) + ln(m-1) + .. + ln(1))
	 * 由上可知 C(n,m) = e^ln(C(n,m)),
	 * 并且由公式右侧可知,m 越小计算量越小
	 * ∵ C(n,m) = C(n,n-m)
	 * ∴ 当 m>n/2.0时,可改为计算 C(n,n-m)
	 * @param n
	 * @param m
	 * @return
	 */
	public static long getCnm(int n,int m){
		if (n < 0 || m < 0){
			throw new IllegalArgumentException("n,m must be > 0");
		}
		if (n == 0 || m == 0){
			return 1;
		}
		if (m > n){
			return 0;
		}
		if (m > n/2.0){
			m = n-m;
		}
		double result = 0.0;
		for (int i=n; i>=(n-m+1); i--){
			result += Math.log(i);
		}
		for (int i=m; i>=1; i--){
			result -= Math.log(i);
		}
		result = Math.exp(result);
		return Math.round(result);
	}
}

 

输出结果:

[0] 123
[1] 124
[2] 125
[3] 126
[4] 134
[5] 135
[6] 136
[7] 145
[8] 146
[9] 156
[10] 234
[11] 235
[12] 236
[13] 245
[14] 246
[15] 256
[16] 345
[17] 346
[18] 356
[19] 456

 

分享到:
评论
1 楼 stanly7 2013-08-16  
组合数用log求然后再算回去,会有差错。在数字比较大的时候就会出错。

相关推荐

    计算组合数并输出组合

    这里我们关注的是“计算组合数”,也就是从一个集合中选择特定数量元素的方法数目,不考虑元素的顺序。这个概念通常用C(n, k)表示,其中n是总元素个数,k是要选择的元素个数。 组合数C(n, k)可以通过以下公式计算:...

    求组合数并列出所有项

    求组合数并列出所有项,输入要求的字符串

    计算组合数,用C语言编程

    - **调用函数计算结果**:调用`combine`函数计算组合数,并输出结果。 #### 2. 函数实现分析 - **函数定义**:`long combine(int x, int y)` 定义了计算组合数的函数。 - **局部变量声明**:声明了三个长整型变量`s...

    输出组合数

    这段代码首先定义了一个`combination`函数,用于计算组合数。然后,程序进入一个无限循环,等待用户输入n和k的值,并输出相应的组合数。如果用户输入'q',则退出程序。 在实际应用中,组合数的计算还可以用到更高效...

    求组合数cnm的mfc实现

    4. **计算组合数**:创建一个辅助函数如CalcCombination(),接收两个整数参数n和m,返回C(n, m)的值。这里可以采用递归或非递归方法实现,非递归方法更适合避免栈溢出,例如使用动态规划存储中间结果。 5. **显示...

    算出从n个不同元素中取出m个元素(m≤n)的组合数——C语言代码

    本篇文章将深入讲解如何用C语言计算组合数,并提供一个简单的C程序示例。 首先,我们要理解组合数的公式。组合数可以用阶乘的形式表示为 C(n, m) = n! / (m!(n-m)!), 其中"!"代表阶乘,即一个正整数n的阶乘是所有...

    VB 用过程求组合数.rar

    VB 用过程求组合数,输入m和n,按等号键可得组合数,来看如下的简单代码:  Private Sub f(m As Integer, p As Long) '自定义通用过程,用于求阶乘 ... Text3 = c '最后求得的组合数在文本框中输出  End Sub

    求组合数 (15 分)PTA

    练习2-18 求组合数 (15 分) 本题要求编写程序,根据公式C​n​m​​=​m!...按照格式“result = 组合数计算结果”输出。题目保证结果在double类型范围内。 输入样例: 2 7 输出样例: result = 21

    vc 求组合数 mfc实现组合

    // 计算组合数 long long combination = CalculateCombination(n, k); // 显示结果 SetDlgItemText(IDC_STATIC_RESULT, FormatCombination(combination)); } else { AfxMessageBox(L"输入错误,请输入整数"); ...

    用递归法计算从n个正整数中选择k个数的不同组合数

    这个公式告诉我们如何直接计算组合数,但当我们使用递归法时,我们并不直接使用这个公式,而是通过递归关系来实现。 递归法的思路是将问题分解为更小的子问题,直到达到基本情况,然后逐步回溯得到原问题的解。在...

    C++中求组合数的各种方法总结详解

    在C++编程中,求组合数是一个常见的数学计算任务,特别是在处理排列组合问题时。组合数,也称为二项式系数,表示从n个不同元素中不重复地选取r个元素的方法数,记为C(n, r)或者"n choose r"。本文将详细介绍三种在...

    易语言源码易语言取元素组合数源码.rar

    这个名为"易语言源码易语言取元素组合数源码.rar"的压缩包文件包含的是使用易语言编写的计算组合数的源代码。组合数,又称为二项式系数,是组合数学中的一个重要概念,常用于解决从n个不同元素中取出k个元素的组合...

    ACM基础模板(宏定义、快读快写、快速幂、gcd、组合数与Lucas定理)(csdn)————程序.pdf

    `lucas()`函数基于Lucas定理计算组合数,该定理用于在模意义下计算组合数,特别适合处理大数。当`a`和`b`小于模`p`时,可以直接使用组合数公式计算,否则递归应用Lucas定理。 以上就是这个ACM基础模板中涉及的主要...

    生成1-10的组合数

    在IT领域,尤其是在编程和算法设计中,"生成1-10的组合数"是一个常见的问题,涉及到数学和计算机科学的交集。这个问题的核心是计算从1到10的整数集合中,按照一定的规则(通常是无序且不重复)选取若干个数的所有...

    计算机数字组合电路与课件

    计算机数字组合逻辑电路是计算机硬件基础中的重要组成部分,它主要涉及如何通过基本的逻辑门(如与门、或门、非门、异或门等)设计出能够执行特定计算任务的电路。这些电路不考虑时间顺序,即它们的输出只取决于当前...

    假设有人民币10的n次方(变量值),输出1元,2元,5元的所有组合数

    标题与描述均提到了一个有趣的数学与编程问题:“假设有人民币10的n次方(变量值),输出1元,2元,5元的所有组合数”。这个问题涉及到的是组合数学中的硬币找零问题,通常在计算机科学领域,尤其是在算法设计与分析...

    c代码-组合数计算啦啦啦

    在编程领域,组合数计算是一项基础且重要的任务,特别是在算法设计和数据分析中。组合数,又称二项式系数,是组合数学中的一个概念,表示在没有重复选择的情况下,从n个不同元素中取出k个元素的方法数。组合数通常用...

    matlab数理统计和数据分析及优化求解:44 实现爱尔兰B公式计算并输出表格.zip

    通过学习和运行这些代码,你可以更直观地了解爱尔兰B公式的MATLAB实现过程,并掌握将计算结果以表格形式输出的方法。 总结来说,MATLAB是进行数理统计、数据分析和优化求解的强大工具,而爱尔兰B公式是投资组合优化...

    组合数字逻辑讲义---2008

    通过写出逻辑函数表达式和制作真值表,我们发现这个电路能够判断输入的4位二进制数的大小,输出Y2、Y1、Y0分别指示数值是否小于等于5、大于5且小于11以及大于等于11,从而实现了数值范围的判断。 设计组合逻辑电路...

    基于C++实现通过组合函数计算n个元素中由k个元素组合的子集个数

    然后,我们可以编写一个`combination`函数来计算组合数: ```cpp int combination(int n, int k) { if (k &gt; n) return 0; return factorial(n) / (factorial(k) * factorial(n - k)); } ``` 在这个函数中,我们...

Global site tag (gtag.js) - Google Analytics