把问题得解空间转化为图或树:
1.子集树:集合中满足条件的子集等,N叉树
2.排列树:确定n个元素满足某种性质的排列,“排列树”并不是N叉树,不能重复选择
0/1背包问题<——>二叉树(0,1)<——>子集树 backtrack(t) ——> 找到t层以下的所有解(每一层代表选不选该货物,0代表不选,1代表选)
O
0/ \1
O O
0 / 1 \ /0 \1
O OO O
if(t > N)
if(cur_value > best_value)
print && record
else{
for(int i = 0; i <= 1; i++){
x(t) = i;
if(i == 0) backtrack(t+1);
else{
if(cur_wight + w(t) <= total_wight){ //约束函数
cur_wight += w(t);
cur_value += v(t);
backtrack(t+1); //递归
cur_wight -= w(t);
cur_value -= v(t); //回溯
}
}
}
}
八皇后问题<——>八叉树<——>子集树问题:backtrack(t) ==>找到t层以下的所有解
board[8][8]
bool isOK(board[][], raw, col) //判断是否符合要求
if(t > N)
print board;
else{
for(int i = 0; i < 8; i++){
if(isOK(board[][],t,i)){ //约束条件
board[t][i] = 1; // 进入下层分支
backtrack(t+1); // 递归
board[t][i] = 0; // 回溯
}
}
}
迷宫问题<——>四叉树<——>子集树问题:backtrack(x,y)==>从x,y走到x_end,y_end的所有情况
问题描述,例如此图,确定一组(x_end, y_end)(假设恰好为右下角),从(x,y)到(x_end,y_end)的所有通路,其中0代表墙,无法通过,如果不能到达,返回false。
Maze[4][6]
bool isOK(Maze[][], x, y) //判断是否符合要求 return Maze[x][y] != 0;
if(x == x_end && y == y_end)
print and record;
else{
path.push_back({x,y});
Maze[x][y] = 0;
if(isOK(Maze,x-1,y)) backtrack(x-1,y);
if(isOK(Maze,x+1,y)) backtrack(x+1,y);
if(isOK(Maze,x,y-1)) backtrack(x,y-1);
if(isOK(Maze,x,y+1)) backtrack(x,y+1); //相当于for循环
Maze[x][y] = 1;
path.pop_back(); //回溯
}
旅行商问题<——>有先后之分,不去同一个城市两次<——>排列数
root
1 2 3 4
2 3 4 |1 3 4 |1 2 4 |1 2 3 不是一个N叉树
backtrack(t)
{
if(t > n)
print
else{
for(int i = t; i <= n; i++){
swap(x[t],x[i]);
backtrack(t+1);
swap(x[t],x[i]);
}
}
}
旅行商问题只是多了record,best_path_length和cur_path_length以及约束条件和限界条件。