组合优化中整数规划松弛与LP舍入近似算法
许多实际决策问题(如路径规划、资源分配、排班)都可以建模为整数规划(IP):变量只能取整数值(通常是 0 或 1)。但直接求解整数规划在规模稍大时计算量会指数爆炸。一个实用的思路是:先放松整数约束,得到一个容易求解的线性规划(LP),再通过舍入把 LP 解还原成整数解。这个流程就是“LP 松弛 + 舍入近似算法”。本文手把手带你走通这一流程。
第一阶段:理解整数规划与线性规划松弛
1. 定义目标问题
写下一个整数规划的标准形式:
- 目标:最小化 $c^T x$(或最大化)
- 约束:$Ax \leq b$,$x \in \{0,1\}^n$(或非负整数)
例如顶点覆盖问题:每条边至少有一个端点被选,选中的顶点总权重最小。
2. 执行线性规划松弛
去掉 整数约束,将 $x_i \in \{0,1\}$ 替换为 $0 \leq x_i \leq 1$。这就变成了一个线性规划,可以在多项式时间内用单纯形法或内点法求解。
3. 记录结果
记 LP 的最优解为 $x^*$,最优值为 $OPT_{LP}$。由于整数解的解空间是 LP 解空间的子集,必然有 $OPT_{LP} \leq OPT_{IP}$(最小化问题)。因此 $OPT_{LP}$ 是 IP 最优值的一个下界(或上界,取决于问题类型)。
第二阶段:设计舍入策略
得到实数解 $x^*$ 后,需要把它变成整数向量 $x'$,使得 $x'$ 满足原整数约束且目标值尽量接近 $OPT_{IP}$。最常用的方法有两种:确定性舍入 和 随机舍入。
2.1 确定性舍入(阈值法)
1. 设定阈值
选择一个固定阈值 $\theta$(例如 $\theta = 0.5$)。
2. 遍历每个变量
对于每个 $i$,如果 $x_i^* \geq \theta$,则 令 $x'_i = 1$;否则 令 $x'_i = 0$。
3. 验证可行性
通常阈值法会破坏某些约束(例如覆盖约束中需要至少选一个端点)。需要根据具体问题调整阈值或增加后处理步骤。
2.2 随机舍入( Randomized Rounding)
1. 计算概率
把 $x_i^*$ 视作 $x_i=1$ 的概率。即 设置 $\Pr[x'_i = 1] = x_i^*$。
2. 执行独立随机试验
对每个 $i$,生成一个 $[0,1]$ 均匀随机数 $r_i$,若 $r_i \leq x_i^*$ 则 $x'_i = 1$,否则为 0。
3. 重复并取期望
由于随机性,需要分析期望目标值和约束违反概率。通常通过重复多次并取最小(或最大)来获得可行解。
第三阶段:分析近似比
1. 确定目标函数变化
对于最小化问题,希望证明 $E[x'] \leq \alpha \cdot OPT_{IP}$,其中 $\alpha \geq 1$ 称为近似比。
2. 计算期望
利用线性期望:$E[c^T x'] = \sum c_i \Pr[x'_i=1] = \sum c_i x_i^* = c^T x^* = OPT_{LP} \leq OPT_{IP}$。但这只是期望,实际解可能更大,因此需要额外分析最坏情况。
3. 推导边界
常用方法:构造一个可行性引理(例如,约束被满足的概率足够高),然后使用联合界或条件期望来保证解可行且目标值不超界。例如顶点覆盖问题中,使用随机舍入后解可行的概率高,且期望目标值不超过 $2 \cdot OPT_{IP}$,最终得到2-近似算法。
4. 记录最终结论
例如:对于顶点覆盖,LP 松弛 + 随机舍入给出了确定性的 2-近似(通过去随机化,例如用条件期望法将随机算法转为确定算法)。
第四阶段:用经典例子巩固
例:集合覆盖(Set Cover)
1. 建立整数规划
元素集合 $U$,子集族 $S$,每个子集 $s$ 代价 $c_s$。变量 $x_s \in \{0,1\}$ 表示是否选子集 $s$。约束:每个元素 $e$ 至少被一个包含它的子集覆盖:$\sum_{s: e \in s} x_s \geq 1$。
2. 松弛为 LP
将 $x_s \in \{0,1\}$ 放松为 $0 \leq x_s \leq 1$。
3. 应用随机舍入
按概率 $x_s^*$ 独立选择每个子集。每个元素被覆盖的概率至少为 $1 - e^{-1}$(因为 $\prod (1 - x_s^*) \leq e^{-\sum x_s^*} \leq e^{-1}$)。因此重复 $\ln n$ 轮并取并,可使覆盖概率 > 1-1/n,期望代价增加至 $\ln n$ 倍,得到 $O(\log n)$-近似。
4. 去随机化
使用条件期望方法(例如依次决定每个子集是否选),保证最终解代价不超过期望的 $\ln n$ 倍,从而得到确定性 $\ln n$-近似算法。
第五阶段:代码实现示例(Python + LaTeX 注释)
下面展示一个最小化顶点覆盖的 LP 松弛 + 舍入框架(代码仅演示流程,不包含库依赖):
import pulp
import math
# 定义图:顶点列表 V,边列表 E
V = [1,2,3]
E = [(1,2), (2,3)]
c = {v: 1 for v in V} # 权重全为1
# 1. 建立 LP 松弛
prob = pulp.LpProblem("VertexCover_LP", pulp.LpMinimize)
x = {v: pulp.LpVariable(f"x_{v}", lowBound=0, upBound=1) for v in V}
prob += pulp.lpSum(c[v] * x[v] for v in V)
for (u,v) in E:
prob += x[u] + x[v] >= 1
prob.solve(pulp.PULP_CBC_CMD(msg=False))
# 2. 取出 LP 解
x_star = {v: pulp.value(x[v]) for v in V}
# 3. 确定性舍入(阈值 0.5)
threshold = 0.5
x_int = {v: 1 if x_star[v] >= threshold else 0 for v in V}
# 4. 验证可行性(是否覆盖所有边)
feasible = all(x_int[u] + x_int[v] >= 1 for (u,v) in E)
print("LP 解:", x_star)
print("舍入后整数解:", x_int)
print("是否可行:", feasible)
print("目标值:", sum(c[v] * x_int[v] for v in V))
关键总结(无须额外废话)
- 整数规划 → LP 松弛:去掉整数约束,得到下界。
- LP 解 → 整数解:通过确定性舍入或随机舍入。
- 近似比分析:证明舍入后的解目标值不超过原整数最优值的常数倍(如 2 倍、$\ln n$ 倍)。
- 核心技巧:利用线性规划的对偶性、期望分析和条件期望去随机化。
以上是组合优化中“LP 松弛 + 舍入”的完整实操流程。按此方法,你可以为任意整数规划问题设计并证明一个近似算法。

暂无评论,快来抢沙发吧!