01分数规划解析(转载)

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


01分数规划

转载于此位大佬:

张天翔

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


前置技能

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

问题模型1

基本01分数规划问题

给定n个二元组(valuei,costi),valuei是选择此二元组获得的价值(非负),costi是选择此二元组付出的代价(非负),设xi(xi∈{0,1})代表第i个二元组的选与不选,最大(小)化下式 

maximize(or minimize)   r=∑valuei⋅xi∑costi⋅xi

 

下面先说最大化

解决方法

二分法

设r最大值为r∗, 

r∗=∑valuei⋅xi∑costi⋅xi

 

 

∑valuei⋅xi−r∗⋅∑costi⋅xi=0

 

设一个函数,自变量为r值, 

f(r)=∑valuei⋅xi−r∗⋅∑costi⋅xi

 

观察这个函数,假如{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)}? 

f(r)=∑valuei⋅xi−r⋅∑costi⋅xi=∑(valuei−r⋅costi)⋅xi

 

二分一个r时,每个二元组的valuei−r⋅costi 都可以求出,设其为weighti,现在的目标就是找到一组{xi}使得∑wighti⋅xi最大(即求max{f(r)})。怎么找到这一组{xi},或者直接求得max{f(r)}呢?具体问题具体分析,经常借助最短路算法判断是否存在负环。下面会有几道例题。

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

Dinkelbach算法

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

思考上述二分算法的思路,设二分过程中某一个二分值为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


问题模型2

最优比率生成树

带权无向图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,也就是求最大生成树,按最大生成树权值的正负性就可以二分了。最小化就求最小生成树。

Dinkelbach算法

当前答案r,边赋值weighti=valuei−r⋅costi,同样求最大生成树,找到max{f(r)}对应的边集{xi},也就是最大生成树的边集。对这个边集找横截距当做下一次答案。横截距是啥呢? 

f(r)=B−A⋅rrr=0=B/A=∑valuei⋅xi∑costi⋅xi


最小化就求最小生成树。

 

例题

[POJ2728]Desert King


问题模型3

最优比率环

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

解决方法

套用01分数规划模型,点权为valuei,边权为costi,一个环为C 
问题要求最大化∑valuei∑costi,(i∈C) 
边数和点数是相同的,但上述式子表述不是很正确,意会即可。 
若答案为r∗,那么任意一个环 

∑valuei∑costi∑valueir∗⋅∑costi−∑valuei≤r∗≤r∗⋅∑costi≥0

 

最小化时 

∑valuei∑costi∑valuei∑valuei−r∗⋅∑costi≥r∗≥r∗⋅∑costi≥0

 

二分法

设当前答案r, 
r<r∗,至少存在一个环,r⋅∑costi−∑valuei<0,即存在负权回路(将边权设为r⋅costi−valuei,不是提前算出,而是在更新路径的时候从哪个点访问到这条边的就将这条边设为相应点权与边权的对应值); 
r≥r∗,则不存在负环。

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

最小化时边权设为 ∑valuei−r⋅∑costi即可,同样也是更新时算出此值。

以上具体实现看例题。

Dinkelbach算法

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

例题

[POJ3621]Sightseeing Cows


问题模型4

最大密度子图

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


更多

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


参考资料

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

全部评论

相关推荐

02-12 20:22
重庆大学 Java
字节暑期刚入职四天,因为是年前,所以很多正职都放假走了,也就没有给我分配mt,然后有一个老哥在我来的时候给我发了一个landing手册,然后还有关于部门业务的白皮书,还有一些业务代码。然后本人是java面的,进来第一次接触go语言&nbsp;前面几天熟悉了一下go的语法和go的框架,可以读但是还不太会写,然后业务白皮书也看的很头疼,包括landing手册里要了解的很多东西说实话我看文档真的快看死了,一个嵌套一个,问题是我还完全不知道咋用这个我了解的东西,还有就是那个项目代码,那个老哥喊我去写写单测,熟悉一下go的语法,但也进行的很困难(这是我第一段实习,之前都是springboot那一套,真不太熟悉这个)想问问大家的建议,就是我从现在开始到在开年回来之前应该做些什么,我目前就一个想法&nbsp;就是复现一个landing手册上的go框架小项目&nbsp;就是相当于帮自己锻炼锻炼怎么写go&nbsp;或者各位大佬有没有更好的锻炼go语法的建议还有就是大家都在说vibe&nbsp;coding,那我应该怎么锻炼自己使用ai的能力,感觉我除了给一些需求然后它给我生成代码,好像就没别的用法了,那些什么工作流、拆解、skill啥的都不知道从哪一个地方开始,包括我现在正在实习,不知道精力该怎么分配,去网上想找找关于agent开发的一些学习流程,说实话,众说纷纭,有的是从python开始打基础然后系统学那些rag&nbsp;prompt&nbsp;langchain&nbsp;mcp等等,有的是说直接找一个github上的ai项目然后反复问ai,我确实有点迷茫,恳求各位大佬能留下你们宝贵的建议,我一定认真反复深刻学习有一说一&nbsp;我觉得字节饭挺好吃的!
Jasonnnnnn...:直接把项目代码喂给AI然后让它帮你分析,如果组里已经有一些流程图总结的话最好,没有的话自己画一个 Go的话其实只要把基础语法搞明白就行了,项目里很多都是直接让ai帮你写好然后自己稍微改下,不用学的特别深 ai的话,可以自己写一些md文件来搞点小东西,但除非你打算转算法,否则不用把rag langchain学的特别深,了解下就行了
字节跳动公司福利 1371人发布
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务