论坛首页 Java企业应用论坛

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

浏览 2251 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-05-25  
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;
			}
		}
	}

}




 
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics