一,回溯算法的基本思想
回溯法从根节点出发,以深度优先搜素整个解空间。这个根节点成为活节点,成为当前的扩展节点。在当前扩展节点处,搜索向纵深方向移至一个新节点,这个新节点成为新的活节点,并成为当前扩展节点。如果在当前扩展节点处不能再向纵深方向移动,则当前扩展节点就成为死节点。此时,应往回移动至最近一个活节点处,并使这个活节点成为当前扩展节点。回溯法以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已无活节点时为止。
二,子集树与排列树
子集树与排列数是用回溯法解问题时,常遇到的两种类型的解空间树。
1,子集树算法框架
void BackTrack(int i){
if(i >= n ){
//代码
}
if(c + w[i] <= load){
c += w[i];
x[i] = 1;
BackTrack(i + 1);
c -= w[i];
}
x[i] = 0;
BackTrack(i + 1);
} 2,排列数算法框架
void BackTrack(int i){
if(i >= n ){
//代码
}
for(int j = i; j <n; j ++){
c += w[x[j]];
if(c > best){
Swap(i, j);
BackTrack(i + 1);
Swap(i, j);
}
c -= w[x[j]];
}
} 三,常见的使用回溯法解决的问题
1,n后问题
class Queue{
private:
int n; //皇后数
int sum; //当前找到的可行方案数
vector<int> x; //存储当前解
public:
Queue(int n):n(n){
sum = 0;
for(int i = 0; i <= n; i ++){
x.push_back(0);
}
}
bool isAttack(int i);
void BackTrack(int i);
int getSum();
};
/**
* 判断在第i层放置一个皇后之后,是否会与前面的皇后发生攻击,
* 如果会发生攻击返回true,否则返回false
*/
bool Queue::isAttack(int i){
for(int j = 1; j < i; j ++){
if(x[j] == x[i] || abs(j - i) == abs(x[j] - x[i])){
return true;
}
}
return false;
}
void Queue::BackTrack(int i){
if(i > n){
sum ++;
} else {
for(int j = 1; j <= n; j ++){
//在第i行、第j列放置一个皇后
x[i] = j;
if(!isAttack(i)){
BackTrack(i + 1);
}
}
}
}
int Queue::getSum(){
BackTrack(1);
return sum;
}
const int INF = 10000000;
const int MaxSize = 20;
class Traveling{
private:
int n; //图中的顶点数
int c; //当前费用
int bestc; //当前最优费用
vector<int> x; //当前解
vector<int> bestx; //当前最优解
vector<vector<int> > e; //图的邻接矩阵
public:
Traveling(int a[][MaxSize], int n);
void BackTrack(int i);
void Swap(int i, int j);
int getBestc();
};
Traveling::Traveling(int a[][MaxSize], int n):n(n){
c = 0;
bestc = INF;
for(int i = 0; i < n; i ++){
x.push_back(i);
bestx.push_back(i);
vector<int> temp(n);
e.push_back(temp);
}
for(int i = 0; i < n; i ++){
for(int j = 0; j < n; j ++){
if(a[i][j] == -1){
e[i][j] = INF;
} else {
e[i][j] = a[i][j];
}
}
}
}
void Traveling::BackTrack(int i){
if(i >= n){
if(e[x[n -1]][x[0]] != INF && c + e[x[n -1]][x[0]] < bestc){
for(int j = 0; j < n; j ++){
bestx[j] = x[j];
}
bestc = c + e[x[n -1]][x[0]];
}
return;
}
for(int j = i; j < n; j ++){
if(i == 0){
Swap(i, j);
BackTrack(i + 1);
Swap(i, j);
} else {
if(e[x[i - 1]][x[j]] != INF && c + e[x[i - 1]][x[j]]< bestc){
Swap(i, j);
c += e[x[i - 1]][x[i]];
BackTrack(i + 1);
c -= e[x[i - 1]][x[i]];
Swap(i, j);
}
}
}
}
void Traveling::Swap(int i, int j){
int temp = x[i];
x[i] = x[j];
x[j] = temp;
}
int Traveling::getBestc(){
BackTrack(0);
return bestc;
}
1882



被折叠的 条评论
为什么被折叠?



