算法之美~回溯算法

如何理解“回溯算法”?
        回溯的处理思想,有点类似枚举搜索。枚举所有的解,找到满足期望的解。为了有规律地枚举所有可能的解,避免遗漏和重复,把问题求解的过程分为多个阶段。每个阶段,都会面对一个 岔路口,先随意选择一条路走,当发现这条路走不通的时候(不符合期望的解),就回退到上一岔路口,另选一种继续走。

八皇后问题
        在一个8×8的棋盘,希望往里放8个棋子(皇后),每个棋子所在的行、列、对角线都不能有另外一个棋子。

算法之美~回溯算法_第1张图片

public class EightQueenDemo {

	/**
	 * 成员变量,下标表示行,值表示queen存储在哪一列
	 */
	private int [] result = new int[8];
	
	/**
	 * 调用方式:cal8queens(0);
	 * @param row
	 */
	public void cal8Queens(int row) {
		// 8个棋子都放置好,打印结果.
		if (row == 8) {
			printQueens(result);
			return;
		}
		
		// 每行都有8种放法.
		for (int column = 0; column < 8; ++column) {
			if(isOk(row, column)) {
				// 将第row行棋子放到column列
				result[row] = column;
				// 考察下一行.
				cal8Queens(row + 1);
			}
		}
	}
	
	/**
	 * 判断row行colum列放置是否合适.
	 * @param row
	 * @param column
	 * @return
	 */
	private boolean isOk(int row, int column) {
		int leftup = column - 1;
		int rightup = column + 1;
		// 逐行往上考察每一行
		for(int i = row-1; i >= 0; --i) {
			// 第i行的column列有棋子
			if (result[i] == column) return false;
			// 考察左上对角线:第i行leftup列有棋子
			if (leftup >=0 ) {
				if (result[i] == leftup) return false;
			}
			// 考察右上对角线:第i行rightup列有棋子
			if (rightup < 8) {
				if (result[i] == rightup) return false;
			}
			--leftup;
			++rightup;
		}
		
		return true;
	}
	
	/**
	 * 打印一个二位矩阵.
	 * @param result
	 */
	private void printQueens(int[] result) {
		for (int row = 0; row < 8; ++row) {
			for (int column = 0; column < 8; ++column) {
				if (result[row] == column) {
					System.out.print("Q ");
				} else {
					System.out.print("* ");
				}
				
			}
			System.out.println();
		}
		System.out.println();
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		final EightQueenDemo entity = new EightQueenDemo();
		entity.cal8Queens(0);
	}

}

两个回溯算法的经典应用
1、0-1背包
    0-1背包问题有很多变体,这里介绍一种比较基础的。有一个背包,背包总的承载重量是weightCapacity。有n个物品,每个物品重量不等,并且不可分割,现在期望选择几件物品,装到背包中。在不超过背包所能装载重量的前提下,如何让背包中物品的总重量最大?

// 存储背包中物品总重量的最大值
private int maxWeight = 0;

// currentWeight 表示当前已经装进去的物品的重量和,i表示考察到哪个物品了;
// weightCapacity 背包重量载荷;items 表示每个物品的重量;n 表示物品个数
// 假设背包可承受重量100,物品个数10,物品重量存储在数组a中,那么可以这样调用f(0, 0, a, 10, 100)
public void f(int i, int currentWeight, int[] items, int n, int weightCapacity) {
	// currentWeight == weightCapacity 表示装满了, i == n 表示已经考察完所有物品
	if (currentWeight == weightCapacity || i == n) {
		if (currentWeight > maxWeight) maxWeight = currentWeight;
		return;
	}
    
    // 当前物品不放包中
	f(i+1, currentWeight, items, n, weightCapacity);
	
	// 已经超过可以背包承受的重量,就不要再装了
	if (currentWeight + items[i] <= weightCapacity) {
		f(i+1, currentWeight + items[i], items, n, weightCapacity);
	}
}

 

你可能感兴趣的:(Java,数据结构&算法,算法)