深搜的剪枝技巧

首先是深搜的模板:

int ans = 最坏情况, now;  // now为当前答案
void dfs(传入数值) {
  if (到达目的地) ans = 从当前解与已有解中选最优;
  for (遍历所有可能性)
    if (可行) {
      进行操作;
      dfs(缩小规模);
      撤回操作;
    }
}

1.剪枝的概念:

实际上,对于搜索,其实就是一棵树:

(树丑,莫要介意)

那么对于没有剪枝的dfs,需要搜索整棵树,而剪枝,就是将其中一部分枝干减掉,使时间复杂度降低。

 2.

剪枝的原则:三个原则:正确性(这是剪枝优化的前提),准确性,高效性;

3.深搜的优化技巧:

  1. 优化搜索顺序
  2. 排除等效冗杂
  3. 记忆化
  4. 最优性剪枝
  5. 可行性剪枝

1.优化搜索顺序:不同的搜索顺序会产生不同的搜索树形态,其规模大小也相差甚远

2.排除等效冗杂:在搜索中,若我们发现沿某几条线路所达到的效果是一样的,那么我们可以只搜索其中的一条

3.记忆化:是啥?:

  • 不依赖任何 外部变量
  • 答案以返回值的形式存在,而不能以参数的形式存在(就是不能将 dfs 定义成这里面的 nowans 不符合要求)。
  • 对于相同一组参数,dfs 返回值总是相同的

模板:

int g[MAXN];  //定义记忆化数组
int ans = 最坏情况, now;
void dfs f(传入数值) {
  if (g[规模] != 无效数值) return;  //或记录解,视情况而定
  if (到达目的地) ans = 从当前解与已有解中选最优;  //输出解,视情况而定
  for (遍历所有可能性)
    if (可行) {
      进行操作;
      dfs(缩小规模);
      撤回操作;
    }
}
int main() {
  ... memset(g, 无效数值, sizeof(g));  //初始化记忆化数组
  ...
}

4.最优性剪枝:在搜索中导致运行慢的原因还有一种,就是在当前解已经比已有解差时仍然在搜索,那么我们只需要判断一下当前解是否已经差于已有解。

模板:

int ans = 最坏情况, now;
void dfs(传入数值) {
  if (now比ans的答案还要差) return;
  if (到达目的地) ans = 从当前解与已有解中选最优;
  for (遍历所有可能性)
    if (可行) {
      进行操作;
      dfs(缩小规模);
      撤回操作;
    }
}

5.可行性剪枝:

在搜索中如果当前解已经不可用了还运行,也是在搜索中导致运行慢的原因。

int ans = 最坏情况, now;
void dfs(传入数值) {
  if (当前解已不可用) return;
  if (到达目的地) ans = 从当前解与已有解中选最优;
  for (遍历所有可能性)
    if (可行) {
      进行操作;
      dfs(缩小规模);
      撤回操作;
    }
}

下面我们来看一个简单的剪枝的例题:【洛谷p1025】数的划分

 下面我们来看一个超多剪枝的例题:【洛谷UVA307】小木棍Sticks

posted @ 2019-06-08 21:53  Sweetness  阅读(720)  评论(0编辑  收藏  举报