01分数规划问题相关算法与题目讲解(二分法与Dinkelbach算法)

01分数规划算法 信息学竞赛 OI ACM 二分 Dinkelbach 最优比率生成树 最优比率环


01分数规划


张天翔

blog.csdn.net/hzoi_ztx
ztx97@qq.com


前置技能

  • 二分思想
  • 最短路算法
  • 一些数学脑细胞?

问题模型1

基本01分数规划问题

给定 n n n个二元组 ( v a l u e i , c o s t i ) (value_i,cost_i) (valuei,costi) v a l u e i value_i valuei是选择此二元组获得的价值(非负), c o s t i cost_i costi是选择此二元组付出的代价(非负),设 x i ( x i ∈ { 0 , 1 } ) x_i(x_i\in \{0,1\}) xi(xi{0,1})代表第 i i i个二元组的选与不选,最大(小)化下式
m a x i m i z e ( o r   m i n i m i z e )     r = ∑ v a l u e i ⋅ x i ∑ c o s t i ⋅ x i maximize(or\ minimize)\ \ \ r = \frac{\sum value_i \cdot x_i}{\sum cost_i\cdot x_i} maximize(or minimize)   r=costixivalueixi

下面先说最大化

解决方法

二分法

r r r最大值为 r ∗ r^* r
r ∗ = ∑ v a l u e i ⋅ x i ∑ c o s t i ⋅ x i r^* = \frac{\sum value_i \cdot x_i}{\sum cost_i\cdot x_i} r=costixivalueixi

∑ v a l u e i ⋅ x i − r ∗ ⋅ ∑ c o s t i ⋅ x i = 0 \sum value_i \cdot x_i - r^*\cdot \sum cost_i\cdot x_i = 0 valueixircostixi=0

设一个函数,自变量为 r r r值,
f ( r ) = ∑ v a l u e i ⋅ x i − r ∗ ⋅ ∑ c o s t i ⋅ x i f(r) =\sum value_i \cdot x_i - r^*\cdot \sum cost_i\cdot x_i f(r)=valueixircostixi

观察这个函数,假如 { x i } \{x_i\} {xi}固定,则这个函数就是坐标系中一条直线( y = B − A ⋅ x y = B - A\cdot x y=BAx),每一组 { x i } \{x_i\} {xi}对应着一条直线,这些直线斜率非正(因为 − A = − ∑ c o s t i ⋅ x i ≤ 0 -A =- \sum cost_i\cdot x_i \le 0 A=costixi0),纵截距非负(因为 B = ∑ v a l u e i ⋅ x i ≥ 0 B =\sum value_i \cdot x_i \ge 0 B=valueixi0 ),如图1。
图1
对于每一条直线,当 f ( r ) = 0 f(r)=0 f(r)=0时,横截距就是这一组的 r r r,那么 r ∗ r^* r就是每条直线横截距的最大值(每组 { x i } \{x_i\} {xi}对应 r r r的最大值)如图2。
图2
在图中上任取一条垂直 x x x轴的竖线,
如果存在直线与这条竖线的交点纵坐标为正,那么最优值一定在当前竖线的右侧;
如果所有直线与这条竖线交点纵坐标为负,那么最优值一定在当前竖线的左侧;
如果所有直线与这条竖线交点纵坐标非正且存在直线与这条竖线交点纵坐标为0,那么当前竖线横坐标即为最优值 r ∗ r^* r
这里写图片描述
按照这个思想,可以二分答案 r r r,那么二分时如何进行判断呢?

选择一个 r r r时需要判断所有 f ( r ) f(r) f(r)的最大值是否为0,如果 m a x { f ( r ) } > 0 max\{f(r)\} > 0 max{f(r)}>0 r < r ∗ r < r^* r<r;如果 m a x { f ( r ) } < 0 max\{f(r)\} < 0 max{f(r)}<0 r > r ∗ r > r* r>r
怎样求 m a x { f ( r ) } max\{f(r)\} max{f(r)}?
f ( r ) = ∑ v a l u e i ⋅ x i − r ⋅ ∑ c o s t i ⋅ x i = ∑ ( v a l u e i − r ⋅ c o s t i ) ⋅ x i \begin{aligned} f(r) &= \sum value_i \cdot x_i - r \cdot \sum cost_i\cdot x_i \\ &= \sum (value_i-r\cdot cost_i) \cdot x_i \end{aligned} f(r)=valueixircostixi=(valueircosti)xi

二分一个 r r r时,每个二元组的 v a l u e i − r ⋅ c o s t i value_i-r\cdot cost_i valueircosti 都可以求出,设其为 w e i g h t i weight_i weighti,现在的目标就是找到一组 { x i } \{x_i\} {xi}使得 ∑ w i g h t i ⋅ x i \sum wight_i\cdot x_i wightixi最大(即求 m a x { f ( r ) } max\{f(r)\} max{f(r)})。怎么找到这一组 { x i } \{x_i\} {xi},或者直接求得 m a x { f ( r ) } max\{f(r)\} max{f(r)}呢?具体问题具体分析,经常借助最短路算法判断是否存在负环。下面会有几道例题。

01分数规划还会与其他问题结合,如网络流等。

D i n k e l b a c h Dinkelbach Dinkelbach算法

这个算法我是在写这篇文章时才知道的。

思考上述二分算法的思路,设二分过程中某一个二分值为 r r r,二分时的判断条件是 m a x { f ( r ) } max\{f(r)\} max{f(r)}的正负性,而这个 r r r除了让 L L L右移或者 R R R左移就没有用了。现在思考某一过程中 r r r m a x { f ( r ) } max\{f(r)\} max{f(r)}能否再被利用。
二分时,假如 m a x { f ( r ) } > 0 max\{f(r)\}>0 max{f(r)}>0这说明最优解在当前 r r r的右侧,于是让 L = r L=r L=r,但是,如果将 L L L移动到 m a x { f ( r ) } max\{f(r)\} max{f(r)}对应直线的横截距呢?显然,算法会变得更快。这个思想就是 D i n k e l b a c h Dinkelbach Dinkelbach算法的内涵。
D i n k e l b a c h Dinkelbach Dinkelbach实质上是一种迭代算法,基于这样的思想:不去二分答案,而是先随便给定一个答案,然后根据更优的解( m a x { f ( r ) } max\{f(r)\} max{f(r)}对应直线的横截距)不断移动答案,逼近最优解。理论上它比二分快些。
在这个算法中,一般将 r r r初始化为 0 0 0

再说最小化

看上面的图,也很好理解,就是最左边的 r r r r ∗ r^* r,当前的 r r r确定时需要用到 m i n { f ( r ) } min\{f(r)\} min{f(r)}
如果 m i n { f ( r ) } > 0 min\{f(r)\}>0 min{f(r)}>0,那么 r < r ∗ r < r^* r<r
如果 m i n { f ( r ) } = 0 min\{f(r)\}=0 min{f(r)}=0,那么 r = r ∗ r = r^* r=r
如果 m i n { f ( r ) } < 0 min\{f(r)\}<0 min{f(r)}<0,那么 r > r ∗ r > r^* r>r

做题时认清哪个是 v a l u e i value_i valuei,哪个是 c o s t i cost_i costi,再记住上面几张图,基本不会出错了。

两种算法的比较

D i n k e l b a c h Dinkelbach Dinkelbach算法的弊端就是需要保存解。这两个算法解决统一问题实际上都有可能快些。
我觉着我一般还是用二分。。。。

例题

[POJ2976]Dropping tests


问题模型2

最优比率生成树

带权无向图 G G G, 对于图中每条边 e i e_i ei, 都有 v a l u e i value_i valuei c o s t i cost_i costi,现在求一棵生成树 T T T,最大(小)化 ∑ v a l u e i ∑ c o s t i , e i ∈ T \frac{\sum value_i}{\sum cost_i},e_i\in T costivaluei,eiT

解决方法

套用01分数规划模型,如果 e i ∈ T e_i\in T eiT x i = 1 x_i=1 xi=1否则 x i = 0 x_i=0 xi=0

二分法

二分答案 r r r,边赋值 w e i g h t i = v a l u e i − r ⋅ c o s t i weight_i = value_i-r\cdot cost_i weighti=valueircosti,因为是生成树,边的数量确定,那么 m a x { f ( r ) } max\{f(r)\} max{f(r)}需要选取前 ∣ G ∣ − 1 |G|-1 G1大的 w e i g h t i weight_i weighti,也就是求最大生成树,按最大生成树权值的正负性就可以二分了。最小化就求最小生成树。

D i n k e l b a c h Dinkelbach Dinkelbach算法

当前答案 r r r,边赋值 w e i g h t i = v a l u e i − r ⋅ c o s t i weight_i = value_i-r\cdot cost_i weighti=valueircosti,同样求最大生成树,找到 m a x { f ( r ) } max \{f(r)\} max{f(r)}对应的边集 { x i } \{x_i\} {xi},也就是最大生成树的边集。对这个边集找横截距当做下一次答案。横截距是啥呢?
f ( r ) = B − A ⋅ r = 0 r = B / A r = ∑ v a l u e i ⋅ x i ∑ c o s t i ⋅ x i \begin{aligned} f(r)=B-A\cdot r &= 0 \\ r&=B/A \\ r &=\frac{\sum value_i \cdot x_i}{ \sum cost_i\cdot x_i} \end{aligned} f(r)=BArrr=0=B/A=costixivalueixi
最小化就求最小生成树。

例题

[POJ2728]Desert King


问题模型3

最优比率环

给定有点权和边权的图,求一个环,使得环的点权和与边权和的比值最大。

解决方法

套用01分数规划模型,点权为 v a l u e i value_i valuei,边权为 c o s t i cost_i costi,一个环为 C C C
问题要求最大化 ∑ v a l u e i ∑ c o s t i , ( i ∈ C ) \frac{\sum value_i }{\sum cost_i},(i\in C) costivaluei,(iC)
边数和点数是相同的,但上述式子表述不是很正确,意会即可。
若答案为 r ∗ r^* r,那么任意一个环
∑ v a l u e i ∑ c o s t i ≤ r ∗ ∑ v a l u e i ≤ r ∗ ⋅ ∑ c o s t i r ∗ ⋅ ∑ c o s t i − ∑ v a l u e i ≥ 0 \begin{aligned} \frac{\sum value_i }{\sum cost_i}&\le r^* \\ \sum value_i&\le r^*\cdot \sum cost_i \\ r^*\cdot \sum cost_i -\sum value_i &\ge 0 \end{aligned} costivalueivalueircostivalueirrcosti0

最小化时
∑ v a l u e i ∑ c o s t i ≥ r ∗ ∑ v a l u e i ≥ r ∗ ⋅ ∑ c o s t i ∑ v a l u e i − r ∗ ⋅ ∑ c o s t i ≥ 0 \begin{aligned} \frac{\sum value_i }{\sum cost_i}&\ge r^* \\ \sum value_i&\ge r^*\cdot \sum cost_i \\ \sum value_i - r^*\cdot \sum cost_i &\ge 0 \end{aligned} costivalueivalueivalueircostirrcosti0

二分法

设当前答案 r r r
r < r ∗ r < r^* r<r,至少存在一个环, r ⋅ ∑ c o s t i − ∑ v a l u e i < 0 r \cdot \sum cost_i -\sum value_i < 0 rcostivaluei<0,即存在负权回路(将边权设为 r ⋅ c o s t i − v a l u e i r\cdot cost_i-value_i rcostivaluei,不是提前算出,而是在更新路径的时候从哪个点访问到这条边的就将这条边设为相应点权与边权的对应值);
r ≥ r ∗ r\ge r^* rr,则不存在负环。

求负环可以用Bellman-Ford,但是比较慢,一般用spfa算法求负环
具体判断方法为,一个点不能入队 n n n次,否则有负环;一条最短路径长度不能到 n n n,否则有负环。两个判断方法可以同时使用。

最小化时边权设为 ∑ v a l u e i − r ⋅ ∑ c o s t i \sum value_i -r \cdot \sum cost_i valueircosti即可,同样也是更新时算出此值。

以上具体实现看例题。

D i n k e l b a c h Dinkelbach Dinkelbach算法

如果用这个算法需要记录下来一个负环,实现还是能实现的,但是没有二分+spfa好写。

例题

[POJ3621]Sightseeing Cows


问题模型4

最大密度子图

这个问题会写在网络流总结中。


更多

更多题目在01分数规划中。


参考资料

【1】KirisameMarisa - NYIST 914Yougth的最大化【二分搜索/Dinkelbach算法】
【2】PerSeAwe - [Algorithm]01分数规划

相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页