434
社区成员
发帖
与我相关
我的任务
分享这道题属于求路径问题,是n后问题的一个变形,可以套用递归回溯法求n后问题的框架来解决。
用解向量(x1, x2,....,xn)表示该问题的一个可能解,其中:
这是一颗有n+1层的m叉树,每一个结点都有m个后继
每个结点都对应有三个状态:
bool place (int t) {
if (tepc > d || tepw >= w)
return false;
return true;
}
回溯法是一种组织得井井有条得穷举式搜索法,适用于求解一些组合数相当大的问题。我的理解是先尝试走该分支,不可行就回头试另一个分支。
与最优值比较。每一步都将当前状态与最优值比较,根据题目要求进行判断:若已经大于或小于最优值了则进行剪枝;
宽松限界。不考虑约束条件,将剩余的所有都加起来,若得到的值仍然比最优值大或小,则进行剪枝;
严格限界。采用贪心算法,精确计算上界。引用上界函数后,在到达一个叶结点时不必再检查该叶结点是否优于当前最优解,因为上界函数使算法搜索到的每个叶结点都是迄今为止找到的最优解。
子集树(2叉树)
(1) 适用于求子集问题,即从n个元素的集合S种找出满足某个性质的子集
(2) 解向量为n维向量(x1, x2,...,xn),xi可以取0或1,表示选或不选
(3) 通常有2^n个叶结点,时间复杂度O(2^n)
(4) e.g. 0-1背包问题
(5) 算法框架如下
void backtrack (int t) {
if (t > n) {
output(x);
return;
}
//选,进入左子树
if (...) {
x[t] = 1;
backtrack(t+1);
}
//不选,进入右子树
if (...) {
x[t] = 0;
backtrack(t+1);}
}
排列树
(1) 适用于求排列问题,即确定n个元素的满足某种性质的排列
(2) 解向量为n维向量(x1,x2,...,xn),x1~xn全排列对应的解向量组成解空间
(3) 通常有n!个叶结点,时间复杂度O(n!)
(4) e.g. 旅行售货员问题
(5) 算法框架如下:
void backtrack(int t) {
if (t > n) {
output(x);
return;
}
//x[1]~x[t-1]已经确定,要获得x[t]~x[n]的不同组合
for (int i = t; i <= n; i++) {
if (...) {
swap (x[t],x[i]);
backtrack(t+1);
swap(x[t], x[i]);
}
}
}
k叉树
(1) 适用于求路径问题,即找到一条路径就可以得到解
(2) 解向量n维向量(x1,x2,...,xn),xi取1~m任意一个
(3) 每个结点都有k个后继,通常有k^(n+1)-1个结点,时间复杂度O(k^n),n为解的路径长度
(4) e.g. n后问题
(5) 算法框架如下:
void backtrack(int t) {
if (t > n) {}
else {
//第t个选哪个?都试一遍
for (int i = 1; i <= m; i++) {
x[t] = i;
if (place(t))
backtrack(t+1);
}
}
}