Commit e4331a90 authored by ouuan's avatar ouuan
Browse files

style(search/opt): change headline to list; format ex problem

parent 072d0c33
Loading
Loading
Loading
Loading
+46 −55
Original line number Diff line number Diff line
@@ -96,17 +96,11 @@ void dfs(传入数值) {

剪枝思路有很多种,大多需要对于具体问题来分析,在此简要介绍几种常见的剪枝思路。

### 极端法
- 极端法:考虑极端情况,如果最极端(最理想)的情况都无法满足,那么肯定实际情况搜出来的结果不会更优了。

考虑极端情况,如果最极端(最理想)的情况都无法满足,那么肯定实际情况搜出来的结果不会更优了
- 调整法:通过对子树的比较剪掉重复子树和明显不是最有“前途”的子树

### 调整法

通过对子树的比较剪掉重复子树和明显不是最有“前途”的子树。

### 数学方法

比如在图论中借助连通分量,数论中借助模方程的分析,借助不等式的放缩来估计下界等等。
- 数学方法:比如在图论中借助连通分量,数论中借助模方程的分析,借助不等式的放缩来估计下界等等。

## 例题

@@ -146,17 +140,14 @@ void dfs(传入数值) {
    5
    ```

### 分析

由于每个人都必须分配到工作,在这里可以建一个二维数组 `time[i][j]` ,用以表示 $i$ 个人完成 $j$ 号工作所花费的时间。给定一个循环,从第 1 个人开始循环分配工作,直到所有人都分配到。为第 $i$ 个人分配工作时,再循环检查每个工作是否已被分配,没有则分配给 $i$ 个人,否则检查下一个工作。可以用一个一维数组 `is_working[j]` 来表示第 $j$ 号工作是否已被分配,未分配则 `is_working[j]=0` ,否则 `is_working[j]=1` 。利用回溯思想,在工人循环结束后回到上一工人,取消此次分配的工作,而去分配下一工作直到可以分配为止。这样,一直回溯到第 1 个工人后,就能得到所有的可行解。

检查工作分配,其实就是判断取得可行解时的二维数组的第一维下标各不相同并且第二维下标各不相同。而我们是要得到完成这 $n$ 份工作的最小时间总和,即可行解中时间总和最小的一个,故需要再定义一个全局变量 `cost_time_total_min` 表示目前找到的解中最小的时间总和,初始 `cost_time_total_min``time[i][i]` 之和,即对角线工作时间相加之和。在所有人分配完工作时,比较 `count``cost_time_total_min` 的大小,如果 `count` 小于 `cost_time_total_min` ,说明找到了一个最优解,此时就把 `count` 赋给 `cost_time_total_min`

但考虑到算法的效率,这里还有一个剪枝优化的工作可以做。就是在每次计算局部费用变量 `count​` 的值时,如果判断 `count` 已经大于 `cost_time_total_min` ,就没必要再往下分配了,因为这时得到的解必然不是最优解。

### 参考代码

```c++
??? note "参考代码"
    ```C++
    #include <cstdio>
    #define N 16
    int is_working[N] = {0};  // 某项工作是否被分配