01分数规划算法 信息学竞赛 OI ACM 二分 Dinkelbach 最优比率生成树 最优比率环
01分数规划
张天翔
blog.csdn.net/hzoi_ztx
[email protected]
给定 n 个二元组 (valuei,costi) , valuei 是选择此二元组获得的价值(非负), costi 是选择此二元组付出的代价(非负),设 xi(xi∈{0,1}) 代表第 i 个二元组的选与不选,最大(小)化下式
下面先说最大化
设 r 最大值为 r∗ ,
设一个函数,自变量为 r 值,
观察这个函数,假如 {xi} 固定,则这个函数就是坐标系中一条直线( y=B−A⋅x ),每一组 {xi} 对应着一条直线,这些直线斜率非正(因为 −A=−∑costi⋅xi≤0 ),纵截距非负(因为 B=∑valuei⋅xi≥0 ),如图1。
对于每一条直线,当 f(r)=0 时,横截距就是这一组的 r ,那么 r∗ 就是每条直线横截距的最大值(每组 {xi} 对应 r 的最大值)如图2。
在图中上任取一条垂直 x 轴的竖线,
如果存在直线与这条竖线的交点纵坐标为正,那么最优值一定在当前竖线的右侧;
如果所有直线与这条竖线交点纵坐标为负,那么最优值一定在当前竖线的左侧;
如果所有直线与这条竖线交点纵坐标非正且存在直线与这条竖线交点纵坐标为0,那么当前竖线横坐标即为最优值 r∗ 。
按照这个思想,可以二分答案 r ,那么二分时如何进行判断呢?
选择一个 r 时需要判断所有 f(r) 的最大值是否为0,如果 max{f(r)}>0 则 r<r∗ ;如果 max{f(r)}<0 则 r>r∗ 。
怎样求 max{f(r)} ?
二分一个 r 时,每个二元组的 valuei−r⋅costi 都可以求出,设其为 weighti ,现在的目标就是找到一组 {xi} 使得 ∑wighti⋅xi 最大(即求 max{f(r)} )。怎么找到这一组 {xi} ,或者直接求得 max{f(r)} 呢?具体问题具体分析,经常借助最短路算法判断是否存在负环。下面会有几道例题。
01分数规划还会与其他问题结合,如网络流等。
这个算法我是在写这篇文章时才知道的。
思考上述二分算法的思路,设二分过程中某一个二分值为 r ,二分时的判断条件是 max{f(r)} 的正负性,而这个 r 除了让 L 右移或者 R 左移就没有用了。现在思考某一过程中 r 与 max{f(r)} 能否再被利用。
二分时,假如 max{f(r)}>0 这说明最优解在当前 r 的右侧,于是让 L=r ,但是,如果将 L 移动到 max{f(r)} 对应直线的横截距呢?显然,算法会变得更快。这个思想就是 Dinkelbach 算法的内涵。
Dinkelbach 实质上是一种迭代算法,基于这样的思想:不去二分答案,而是先随便给定一个答案,然后根据更优的解( max{f(r)} 对应直线的横截距)不断移动答案,逼近最优解。理论上它比二分快些。
在这个算法中,一般将 r 初始化为 0 。
再说最小化
看上面的图,也很好理解,就是最左边的 r 为 r∗ ,当前的 r 确定时需要用到 min{f(r)} 。
如果 min{f(r)}>0 ,那么 r<r∗ ;
如果 min{f(r)}=0 ,那么 r=r∗ ;
如果 min{f(r)}<0 ,那么 r>r∗ 。
做题时认清哪个是 valuei ,哪个是 costi ,再记住上面几张图,基本不会出错了。
Dinkelbach 算法的弊端就是需要保存解。这两个算法解决统一问题实际上都有可能快些。
我觉着我一般还是用二分。。。。
[POJ2976]Dropping tests
带权无向图 G , 对于图中每条边 ei , 都有 valuei 和 costi ,现在求一棵生成树 T ,最大(小)化 ∑valuei∑costi,ei∈T
套用01分数规划模型,如果 ei∈T 则 xi=1 否则 xi=0 。
二分答案 r ,边赋值 weighti=valuei−r⋅costi ,因为是生成树,边的数量确定,那么 max{f(r)} 需要选取前 |G|−1 大的 weighti ,也就是求最大生成树,按最大生成树权值的正负性就可以二分了。最小化就求最小生成树。
当前答案 r ,边赋值 weighti=valuei−r⋅costi ,同样求最大生成树,找到 max{f(r)} 对应的边集 {xi} ,也就是最大生成树的边集。对这个边集找横截距当做下一次答案。横截距是啥呢?
[POJ2728]Desert King
给定有点权和边权的图,求一个环,使得环的点权和与边权和的比值最大。
套用01分数规划模型,点权为 valuei ,边权为 costi ,一个环为 C
问题要求最大化 ∑valuei∑costi,(i∈C)
边数和点数是相同的,但上述式子表述不是很正确,意会即可。
若答案为 r∗ ,那么任意一个环
最小化时
设当前答案 r ,
r<r∗ ,至少存在一个环, r⋅∑costi−∑valuei<0 ,即存在负权回路(将边权设为 r⋅costi−valuei ,不是提前算出,而是在更新路径的时候从哪个点访问到这条边的就将这条边设为相应点权与边权的对应值);
r≥r∗ ,则不存在负环。
求负环可以用Bellman-Ford,但是比较慢,一般用spfa算法求负环
具体判断方法为,一个点不能入队 n 次,否则有负环;一条最短路径长度不能到 n ,否则有负环。两个判断方法可以同时使用。
最小化时边权设为 ∑valuei−r⋅∑costi 即可,同样也是更新时算出此值。
以上具体实现看例题。
如果用这个算法需要记录下来一个负环,实现还是能实现的,但是没有二分+spfa好写。
[POJ3621]Sightseeing Cows
这个问题会写在网络流总结中。
更多题目在01分数规划中。
【1】KirisameMarisa - NYIST 914Yougth的最大化【二分搜索/Dinkelbach算法】
【2】PerSeAwe - [Algorithm]01分数规划