1.回溯算法是什么
回溯算法又称“穷举法”,是一种通用解题的方法。
解题框架:
void backtrack (int t)
{
if (t>n) output(x); //叶子节点,输出结果,x是可行解
else
for i = 1 to k//当前节点的所有子节点
{
x[t]=value(i); //每个子节点的值赋值给x
//满足约束条件和限界条件
if (constraint(t)&&bound(t))
//保存状态
backtrack(t+1); //递归下一层
//回溯
}
}
2.例题
解空间是子集树
package recall;
import java.util.Scanner;
/**
* 问题描述
* 给定n中物品和一个揹包,揹包容量是C 物品i的重量是wi,
* 物品i的价值是vi 问如何装物品,使得揹包内的总价值最大
* @author Administrator
*
*/
public class Test1
{
public static int itemNum; // 物品总数
public static int ItemTotalWeight; // 揹包总容量
public static int[] w; // 各个物品的重量
public static int[] v; // 各个物品的价值
public static int[] x; // 记录当前物品的放入状态
public static int currentWeight = 0; // 当前总重量
public static int currentValue = 0; // 当前总价值
public static int bestValue = 0; // 最大价值
public static int[] bestItems; // 存放最大价值的各个物品 1表示放入,0表示不放入
public static void backTrack(int t)
{
// 到达遍历临界条件,遍历到叶子
if (t > itemNum - 1)
{
// 保存最优解
if (currentValue > bestValue)
{
bestValue = currentValue;
System.arraycopy(x, 0, bestItems, 0, x.length);
}
} else
{
// 对每个物品进行遍历,只有0,1
for (int i = 0; i <= 1; i++)
{
// 第t个物品进行 i状态
x[t] = i;
if (i == 0)
{ // 不放入状态,则对下个物品进行
backTrack(t + 1);
} else
{ // 放入状态,对约束条件进行判断
if (currentWeight + w[t] <= ItemTotalWeight)
{ // 可以放得下,保存状态
currentValue += v[t];
currentWeight += w[t];
backTrack(t + 1);
// 回到没放入之前的状态
currentValue -= v[t];
currentWeight -= w[t];
}
}
}
}
}
public static void main(String[] args)
{
Scanner scanner = new Scanner(System.in);
while (true)
{
System.out.println("请输入有几种物品:");
itemNum = scanner.nextInt();
System.out.println("请输入揹包容量:");
ItemTotalWeight = scanner.nextInt();
w = new int[itemNum];
v = new int[itemNum];
x = new int[itemNum];
bestItems = new int[itemNum];
System.out.println("请输入各个物品的总量:");
for (int i = 0; i < w.length; i++)
{
w[i] = scanner.nextInt();
}
System.out.println("请输入各个物品的价值:");
for (int i = 0; i < v.length; i++)
{
v[i] = scanner.nextInt();
}
backTrack(0);
System.out.println("最大价值:" + bestValue);
for (int i = 0; i < bestItems.length; i++)
{
System.out.println("最优解:" + bestItems[i]);
}
}
}
}
package recall;
import java.util.Scanner;
/**
* 问题描述
* 给定一个n阶迷宫,给定起始点,给定终点
* 找出从起始点到终点的最短路径
* @author Administrator
*
*/
public class Test2
{
public static int n=10;
public static int state = 0 ; //0上 1下 2左 3右
public static int[][] map={
{0,0,1,1,1,1,1,1,1,1}, //0
{1,0,0,1,1,0,0,1,0,1}, //1
{1,0,0,1,0,0,0,1,0,1}, //2
{1,0,0,0,0,1,1,0,0,1}, //3
{1,0,1,1,1,0,0,0,0,1}, //4
{1,0,0,0,1,0,0,0,0,1}, //5
{1,0,1,0,0,0,1,0,0,1}, //6
{1,0,1,1,1,0,1,1,0,1}, //7
{1,1,0,0,0,0,0,0,0,0}, //8
{1,1,1,1,1,1,1,1,1,0} //9
// 0 1 2 3 4 5 6 7 8 9
};
public static int endX = 9;
public static int endY = 9;
public static int currentValue = 0;
public static int[][] currentLoads = new int[10][10];
public static int bestValue = 999;
public static int[][] bestLoads = new int[10][10];
public static void main(String[] args)
{
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
currentLoads[i][j] = map[i][j];
}
}
backTrace(0,0);
System.out.println("最短路径:"+bestValue);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
System.out.print(bestLoads[i][j]+" ");
}
System.out.println();
}
}
private static void backTrace(int x, int y)
{
//到达终点
if(x==endX && y==endY){
currentValue++;
currentLoads[x][y]=2;
if(currentValue < bestValue){
for(int i=0; i<n ;i++){
for(int j=0;j<n;j++){
bestLoads[i][j] = currentLoads[i][j];
}
}
bestValue = currentValue;
}
currentValue--;
currentLoads[x][y]=0;
}
else if(x>=n || y>=n ||x< 0 || y< 0){
//出界的路线
}
else{
if(currentLoads[x][y]==0){
currentLoads[x][y] = 2;
currentValue++;
backTrace(x, y+1);
backTrace(x+1, y);
backTrace(x, y-1);
backTrace(x-1, y);
currentValue--;
currentLoads[x][y] = 0;
}
}
}
}
解空间是排列树
package recall;
import java.io.OutputStream;
import java.util.Scanner;
/**
*给定一个整数n,要求列出1-n的全排列
* @author Administrator
*
*/
public class Test3
{
public static int n;
public static int[] flag;
public static int[] value;
public static int count=0;
public static void main(String[] args)
{
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
flag = new int[n];
value = new int[n];
backTrace(0);
System.out.println(count);
}
private static void backTrace(int t)
{
//选完元素
if(t > n-1){
count++;
for(int i=0;i<n;i++){
System.out.print(value[i]+" ");
}
System.out.println();
}else{
for(int i=1;i<=n;i++){
if(flag[i-1]==0){ //还没选过的元素
value[t] = i;
flag[i-1] = 1;
backTrace(t+1);
value[t] = 0;
flag[i-1] = 0;
}
}
}
}
}