`

分享回溯法- 找n个数中r个数的组合

J# 
阅读更多
1. 问题描述: 找n个数中r个数的组合

2. 问题分析:

   (1) 问题的解空间为一组r元一维向量(a1, a2, a3, ...,ar), 1<=ai<=n, 1<=i<=r用一维数组a存储正在搜索的向量。

   (2) 例子。 以n=5, r=3为例:
    
       5  4  3
       5  4  2
       5  4  1
       5  3  2
       5  3  1
       5  2  1
       4  3  2
       4  3  1
       4  2  1
       3  2  1
      
      分析数据的特点,搜索时依次对数组(一维向量)元素a[1]、a[2]、a[3]进行尝试。
      a[ri]        i1 ~ i2
      a[1]尝试范围 5 ~ 3
      a[2]尝试范围 4 ~ 2
      a[3]尝试范围 3 ~ 1
      且有这样的规律:ri+i1 = n+1; ri+i2 = r+1; 后一个元素至少比前一个数小1
     
      归纳为一般情况:
      a[1]尝试的范围为(n ~ r)
      a[2]尝试的范围为(n-1 ~ r-1)
      ...
      a[r]尝试的范围为(n-r+1, 1)

      由此,搜索约束条件为ri+a[ri]>=r+1; 若ri+a[ri]<r+1,就要回溯到元素a[ri-1]搜索;特别地当a[r]=1时,回溯到a[r-1]。

3. Java代码:

package boke;

/**
 * 回溯算法:找n个数中r个数的组合
 * 
 * @since jdk1.5及其以上
 * @author 毛正吉
 * @version 1.0
 * @date 2010.05.24
 * 
 */
public class NumbserCombo {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// 测试例子
		NumbserCombo nc = new NumbserCombo(5, 3, 20);
		nc.comb();

	}

	private int n; // 输入数据n
	private int r; // 输入数据r
	private int[] a; // 解向量

	public NumbserCombo(int _n, int _r, int maxR) {
		n = _n;
		r = _r;
		a = new int[maxR];
	}

	/**
	 * 处理方法
	 */
	public void comb() {
		int i, ri;
		ri = 1;
		a[1] = n;

		while (a[1] >= r) { // a[1]肯定大于等于r的,否则搜到到底了
			if (ri < r) { // 没有搜索到底
				if (ri + a[ri] >= r + 1) { // 是否回溯
					a[ri + 1] = a[ri] - 1;
					ri++;
				} else { // 回溯
					ri--;
					a[ri] = a[ri] - 1;
				}
			} else if (ri == r) {
				for (int j = 1; j <= r; j++) {
					System.out.print(a[j] + " ");
				}
				System.out.println("");

				if (a[ri] == 1) { // 是否回溯
					ri--;
					a[ri] = a[ri] - 1; // 回溯
				} else {
					a[ri] = a[ri] - 1; // 搜索到下一个数
				}
			} else {
				return;
			}
		}
	}

}




 
分享到:
评论
1 楼 bhjackson 2011-09-18  
学习啦,能否详细介绍下回溯的过程?O(∩_∩)O谢谢

相关推荐

    C++回溯算法实验报告

    在这个C++实验中,我们分别通过两个实例来探讨回溯法的应用。 首先,实验的第一个问题是删数问题。这个问题要求在给定的n位正整数a中去掉k个数字,使得剩下的数字排列成的新正整数尽可能大。为了解决这个问题,我们...

    Python基于回溯法子集树模板解决数字组合问题实例

    在本例中,我们讨论的是如何使用回溯法来找到从1到n中选取r个数字的所有可能组合。这个问题可以转化为求解大小为r的子集问题,即在给定集合{1, 2, ..., n}中找出所有包含r个元素的子集。对于n=5和r=3的情况,我们...

    回溯法典型题

    在给定的“邮票题”中,回溯法被用来找到一组邮票面值,使得在不超过M张邮票的限制下,能够组合出从1到最大可能值R的所有整数邮资,但不能组合出R+1。下面将详细解释回溯法以及在本题中的应用。 回溯法的基本思想是...

    从n个数组中取出所有排列组合(Java实现)

    总结来说,从n个数组中取出所有排列组合的Java实现涉及到递归算法、回溯法以及数据结构的操作。理解这些概念并能够熟练运用是成为一名优秀程序员的关键。通过这个例子,我们可以看到如何利用Java的灵活性和表达力来...

    组合数算法

    在回溯法的思想下,找解过程可以叙述如下:首先放弃组合数个数为r的条件,候选组合从只有一个数字1开始。因该候选解满足除问题规模之外的全部条件,扩大其规模,并使其满足上述条件(1),候选组合改为1、2。继续这...

    组合数学- 组合数.rar

    - 数据结构和算法:在动态规划、回溯法、组合优化问题(如旅行商问题)中扮演重要角色。 在“组合数学- 组合数.pdf”这个文档中,可能会详细介绍组合数的概念、性质、计算方法,以及其在不同领域的应用实例。通过...

    计算数字排列组合,任意数字的组合。

    2. **组合的计算**:组合的总数用组合数C(n, r)表示,即从n个不同元素中不重复地取出r个元素的组合数。组合数的计算公式为C(n, r) = n! / [r!(n-r)!]。 3. **算法实现**:在编程中,常用递归或动态规划方法实现排列...

    装载问题(回溯法)报告.doc

    【装载问题(回溯法)】是算法设计与分析领域中的一个重要问题,主要涉及如何高效地安排多个集装箱的装载,以充分利用两艘轮船的载重能力。此问题可以通过回溯法来解决,这是一种试探性的搜索策略,适用于解决约束...

    学习常用算法之(3)回溯法(续)

    在给定的【标题】和【描述】中,我们关注的是如何使用回溯法来解决组合问题,即从给定的自然数集合中找出所有可能的r个数的组合。 【部分内容】中提供的代码是一个Java程序,用于解决从1到n中选取r个数的所有组合...

    c++二分法,回溯法简单核心代码

    在编程领域,C++是一种广泛使用的面向对象的编程语言,其强大的功能和高效性使得它在许多复杂的系统和算法实现中占据重要地位。本话题主要关注两种基础但至关重要的算法:二分法和回溯法。这两者在解决不同类型的...

    combination.docx

    标题中的"combination.docx"显然指的是一个文档,其中包含了关于如何使用R语言生成组合的代码。描述中提到,这个R函数能自动生成从n个不同的元素中取出r个元素的所有可能组合,同时提供了可视化的结果图。这通常涉及...

    回溯法系列问题集合回溯法系列问题集合

    ### 回溯法系列问题详解 #### 回溯法概览 回溯法是一种通过尝试解决子问题,并在发现子问题解不可行时撤回(回溯)的算法设计策略。这种方法广泛应用于解决约束满足问题、优化问题以及决策树搜索等场景。其核心在于...

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

    在求组合数的问题中,回溯法通过维护一个数组a[]来存储当前组合,并在遍历过程中不断尝试选择下一个数,同时满足组合的性质:后一个数大于前一个数且a[i] - i &lt;= n - r + 1。 在程序中,回溯法通过一个递归函数...

    迭代回溯法解决矩阵乘法链问题(C++)

    迭代回溯法是一种用于寻找所有可能解并从中找出最优解的方法。在矩阵乘法链问题中,我们可以采用以下步骤: 1. **形式化表示矩阵乘法链**: - 对于乘号的排序,我们可以考虑每个乘号作为分割点,生成所有可能的...

    程序设计中的算法.doc

    在回溯法的示例3中,同样是为了找出n个数中r个数的组合,但这次采用了一种迭代策略,通过回溯来避免无效的组合。当搜索到不满足条件的状态时,算法会返回到之前的决策点,尝试不同的选择。 这些算法都是程序设计中...

    permutation.docx

    给定标题“permutation.docx”和描述,我们将探讨如何使用R语言编程实现自动生成n个不同元素中取r个元素的所有排列。 `Permutation`函数是一个递归函数,它接受两个参数:n(元素总数)和r(要选择的元素数量)。...

    深优先搜索与回溯算法PPT学习教案.pptx

    1. **子集问题**:给定一个包含n个整数的集合,需要找出所有可能的r个元素的子集。例如,对于集合{1,2,3}和r=2,我们可以得到子集{(1,2), (1,3), (2,3)}。 2. **数的拆分**:给定一个大于1的自然数n,求所有可能的...

    实验6子集和问题的回溯算法设计与实现&#40;报告&#41;.doc

    实验6的主题是“子集和问题的回溯算法设计与实现”,主要目的是通过回溯法解决从一组自然数中找出所有可能的组合的问题。回溯法是一种试探性的搜索策略,它尝试逐步构建候选解,当发现当前解不可能是有效解时,会...

    排列数!

    排列数,也称为排列,是组合数学中的一个基本概念,主要研究从有限个不同元素中取出一部分元素,并按照一定的顺序排列的方法数。在数学符号中,我们通常用nPr或P(n,r)来表示从n个不同的元素中取r个元素进行排列的...

Global site tag (gtag.js) - Google Analytics