题外话:
写题的时候遇到了这个算法,xue微了解一下吧
0/1分数规划
根据楼教主的回忆录,他曾经在2005年的ACM地区赛赛场上秒掉了一道最优比率生成树问题,导致很多人跟风失败
(瑟瑟发抖。。。)
问题描述
给定两个数组, a[i] a [ i ] 表示选取 i i 的收益,表示选取 i i 的代价
如果选取i,定义否则 x[i]=0 x [ i ] = 0
每一个物品只有选或者不选两种方案,求一个选择方案
使得 R=∑a[i]∗x[i]∑b[i]∗x[i] R = ∑ a [ i ] ∗ x [ i ] ∑ b [ i ] ∗ x [ i ] 取得最值
即所有选择物品的总收益/总代价的值最大或是最小
01分数规划问题主要包含一般的01分数规划,最优比率生成树问题,最优比率环问题等
我们将会对这三个问题进行讨论
本文主要讨论最大值的情况
首先我们需要好好的端详一下目标式:
R=∑a[i]∗x[i]∑b[i]∗x[i] R = ∑ a [ i ] ∗ x [ i ] ∑ b [ i ] ∗ x [ i ]
定义一个函数
F(L)=∑a[i]∗x[i]−L∗∑b[i]∗x[i]
F
(
L
)
=
∑
a
[
i
]
∗
x
[
i
]
−
L
∗
∑
b
[
i
]
∗
x
[
i
]
显然这只是对目标式的一个简单的变形
分离参数,得到
F(L):=∑(a[i]−L∗b[i])∗x[i]
F
(
L
)
:=
∑
(
a
[
i
]
−
L
∗
b
[
i
]
)
∗
x
[
i
]
这时我们就会发现,如果L已知的话,
a[i]−L∗b[i]
a
[
i
]
−
L
∗
b
[
i
]
就是已知的
记
d[i]=a[i]−L∗b[i]
d
[
i
]
=
a
[
i
]
−
L
∗
b
[
i
]
,那么
F(L):=∑d[i]∗x[i]
F
(
L
)
:=
∑
d
[
i
]
∗
x
[
i
]
实际上,L就是目标式中的R,最大化R也就是最大化L
F的值是由两个变量共同决定的,即方案X和参数L
对于一个确定的参数L来说,方案的不同会导致对应的F值的不同,那么这些东西对我们有什么用呢?
假设我们已知在存在一个方案X使得 F(L)>0 F ( L ) > 0 ,这能够证明什么?
F(L)=∑a[i]∗x[i]−L∗∑b[i]∗x[i]>0
F
(
L
)
=
∑
a
[
i
]
∗
x
[
i
]
−
L
∗
∑
b
[
i
]
∗
x
[
i
]
>
0
即
∑a[i]∗x[i]∑b[i]∗x[i]>L
∑
a
[
i
]
∗
x
[
i
]
∑
b
[
i
]
∗
x
[
i
]
>
L
也就是说,如果一个方案使得
F(L)>0
F
(
L
)
>
0
,说明存在更优的一个L
显然,d数组是随着L的增大而单调减的
也就是说,存在一个临界的L使得不存在一种方案,能够使
F(L)>0
F
(
L
)
>
0
.
我们猜想,这个时候的L就是我们要求的最优解
之后更大的L值则会造成无论任何一种方案,都会使
F(L)<0
F
(
L
)
<
0
类似于上面的那个变形,我们知道,
F(L)<0
F
(
L
)
<
0
是没有意义的,因为这时候的L是不能够被取得的
当
F(L)=0
F
(
L
)
=
0
时,对应方案的R值恰好等于此时的L值
千万不要把F值同R值混淆
F值是根据我们的变形式求的d数组来计算的,而R值则是我们所需要的真实值,他的计算是有目标式决定的
F值只是提供了一个证据,告诉我们真正最优的R值在哪里,与R值本身并没有什么必然的联系
根据这样的一段性质,很自然的就可以想到二分L值
验证是否存在一组解使得
F(L)>0
F
(
L
)
>
0
,有则移动下界,没有则移动上界
所有的01分数规划都是这种思路,唯一的区别就在于求解时的不同——因为每一道题的限制条件不同,并不是每一个解都是可行解的
比如在普通的数组中,你可以选取1,2,3号元素
但在生成树问题中,若1,2,3号元素恰好构成了一个环,那就不能够同时选择了
具体问题,具体分析
二分是一个非常通用的办法
但是我们来考虑这样的一个问题:二分的时候我们只是用到了
F(L)>0
F
(
L
)
>
0
这个条件,而对于使得
F(L)>0
F
(
L
)
>
0
的这组解所求到的R值没有使用
因为
F(L)>0
F
(
L
)
>
0
,我们已经知道了R是一个更优的解,与其漫无目的的二分,为什么不将解移动到R上去呢?
求01分数规划的另一个方法:Dinkelbach
就是基于这样的一个思想
我们并不去二分答案,而是先随便给定一个答案
然后根据更优的解不断移动答案,逼近最优解
由于ta对每次判定使用的更加充分,所以比二分会快很多
但是,ta的弊端就是需要保存这个解,而我们知道,有时候验证一个解和求得一个解的复杂度是不同的
二分和算法写法都非常简单,各有长处,大家要根据题目谨慎使用
伪代码
//--------------------二分法---------------------
L=...; R=...;
do
{
mid=(L+R)/2;
for (int i=1;i<=X;i++)
D[i]=A[i]-mid*B[i];
if 检查(X) 成功
L=mid;
else R=mid;
}
while (abs(L-R)<eps);
//--------------------Dinkelbach---------------------
L=你随意;
do
{
ans=L;
for (int i=1;i<=X;i++)
D[i]=A[i]-L*B[i];
p=0; q=0;
for (i=每一个元素)
如果元素i在解中
p+=A[i],
q+=B[i];
L=p/q;
}
while (abs(ans-L)<eps);
例题
最优比率生成树问题
问题描述
有带权图G, 对于图中每条边 e[i] e [ i ] , 都有 benifit[i] b e n i f i t [ i ] (收入)和 cost[i] c o s t [ i ] (花费), 我们要求的是一棵生成树 T T , 它使得最大(或最小).
01分数规划
设 x[i] x [ i ] 等于1或0, 表示边 e[i] e [ i ] 是否属于生成树.
则我们所求的比率: R=∑benifit[i]∗x[i]∑cost[i]∗x[i],0≤i<m R = ∑ b e n i f i t [ i ] ∗ x [ i ] ∑ c o s t [ i ] ∗ x [ i ] , 0 ≤ i < m
设函数
F(L)=∑benifit[i]∗x[i]−L∗∑cost[i]∗x[i]
F
(
L
)
=
∑
b
e
n
i
f
i
t
[
i
]
∗
x
[
i
]
−
L
∗
∑
c
o
s
t
[
i
]
∗
x
[
i
]
F(L)=∑(benifit[i]−L∗cost[i])∗x[i]
F
(
L
)
=
∑
(
b
e
n
i
f
i
t
[
i
]
−
L
∗
c
o
s
t
[
i
]
)
∗
x
[
i
]
d[i]=benifit[i]−L∗cost[i]
d
[
i
]
=
b
e
n
i
f
i
t
[
i
]
−
L
∗
c
o
s
t
[
i
]
我们可以兴高采烈地把
F(L)
F
(
L
)
看做以
d
d
为边权的最大生成树
明确两个性质
- 单调递减
证明:因为 cost c o s t 为正数, 所以 F F 随的减小而增大.-
F(max(R))=0
F
(
m
a
x
(
R
)
)
=
0
证明:若 F(max(R))<0,∑benifit[i]∗x[i]−max(R)∗∑cost[i]∗x[i]<0 F ( m a x ( R ) ) < 0 , ∑ b e n i f i t [ i ] ∗ x [ i ] − m a x ( R ) ∗ ∑ c o s t [ i ] ∗ x [ i ] < 0 , 可化为 max(R)<max(R) m a x ( R ) < m a x ( R ) ,矛盾;
若 F(max(R))>=0 F ( m a x ( R ) ) >= 0 , 根据性质1, 当 F(R)=0 F ( R ) = 0 时 R R 最大.
复杂度:
时间:
空间: O(O(MST)) O ( O ( M S T ) )一般的,我们在求MST的时候,Kruskal和Prim都可
不过尽量不要在稠密图上使用Kruskal例题
最优比率环问题
问题描述
求一个环的 {点权和} 除以 {边权和} ,使得那个环在所有环中 {点权和} 除以 {边权和} 最大
求 ∑v[i]∑e[i] ∑ v [ i ] ∑ e [ i ]
其中v是环中点的价值,e是环中边的价值设答案为 ans a n s
则对于所有环都有: ∑v[i]∑e[i]<=ans ∑ v [ i ] ∑ e [ i ] <= a n s
ans∗∑e[i]−∑v[i]>=0 a n s ∗ ∑ e [ i ] − ∑ v [ i ] >= 0
对于答案 k k :
当时,就存在至少一个环 k∗∑e[i]−∑v[i]<0 k ∗ ∑ e [ i ] − ∑ v [ i ] < 0 ,即有负权回路(边权为 k∗e[i]−v[i] k ∗ e [ i ] − v [ i ] )
当 k>=ans k >= a n s 时,就对于所有的环 k∗∑e[i]−∑v[i]>=0 k ∗ ∑ e [ i ] − ∑ v [ i ] >= 0 ,即没有负权回路二分答案,将新的边权设为 k∗e[i]−v[i] k ∗ e [ i ] − v [ i ] ,用 spfa s p f a 来判断负权回路即可
例题
-
F(max(R))=0
F
(
m
a
x
(
R
)
)
=
0