加权区间调度问题详解

时间:2020-12-13 11:42:54

题目要求:

    求区间图的最大加权独立集。(选择一部分互不重叠的区间,使得被选出来的区间权重之和最大)


                                               加权区间调度问题详解

                                                                                                          图一

题目分析:

这类问题可以归结为区间调度问题,这是其中最普通的一类,即加权最大区间调度问题,其求解思路可以通过求最多区间调度(贪婪算法dp[i-1] = dp[i]),无权最大区间(权值为1的动态规划)依次发展过来,其具体思路分析详见http://blog.csdn.net/yutianzuijin/article/details/45116705#。我也从博客中转载了这篇文章,http://blog.csdn.net/lukas_sun/article/details/53770959。向原作者致敬!

 

题目求解:

求解最大权值区间的必要条件就是各最优区间互不冲突,这是这类调度问题共同的影子,只不过它的目标是让各区间的权值和最大。

和所有这种规划问题相同,我们需要对所有区间进行排序,排序原则为结束时间的先后,因为用开始时间排序无法得到各区间明确界限。

首先规定几个记号

O(j): 需求区间{ 1……j }的最优解集

p ( n ): 最大的满足不与第n个区间冲突的区间号

OPT( j ): O( j )的最优解值。

由此定义可以分析得到第p(n)+1, p(n)+2 ,p(n)+3…………n-1个区间都与第n个区间冲突,所以O一定包含对需求区间{1,……p(n)}的最优解(否则可以将其替换成最优解而不影响需求区间n),由于p(n) <= n-1,所以如果n不包含在O里,则其可以转化为对需求区间 {1……n-1}的求解。

则我们的递推模型可以以是否选择第j个区间为构造依据。

加权区间调度问题详解

按照此递推公式可知求解过程:

OPT(3)= 3 (2,3)

OPT(5)= 5+OPT(0)= 5    (1,5) 

OPT(8)= 6+OPT(4)= 6 +OPT(3)= 9  (2,3)、(4,8)

OPT(10)= 1+OPT(9) = 1+OPT(8)=10 (2,3)、(4,8)、(9,10)

OPT(12)= 10+OPT(6)= 10+OPT(5)>10 =15

OPT(14)= 0+OPT(13)= OPT(12)= 15

OPT(15)= 7+OPT(11)= 7+OPT(10)= 17 >OPT( 14 )

OPT(17)= OPT(15)> = 12+OPT (7) = 17

OPT(18)= 4+OPT(16)= 4+OPT(15)= 21>OPT(17)

综上,该图最大权和为21,在其递归算法中的

加权区间调度问题详解

判断条件后将所选的边加入到边的数组中,调用结束后输出这个数组可以得到所选边集:

{(2,3)(4,8)(9,10)(11,15)(16,18)}

若Max()函数和递归判断中的”>”换为“>=”虽然使最大权值不变但可使所选边集发生变化,如此例中OPT(17)= 17,但所选边集为

     {(1,5)(7,17)}

不同于改动前的边集:

{(2,3)(4,8)(9,10)(11,15)}

题目扩展:

这个问题可以转化为求最大加权独立集的问题,这种图论问题广泛应用于DNA测序等方面,且为NP问题,求解困难。即将每条线段转化为图中的一个顶点,将有重叠部分的线段设置为相邻的顶点,每条线段的权值在顶点数据中体现,则上述问题转换为选择图中不相邻的最大权值顶点集。转换后的图如图二所示。

加权区间调度问题详解 

图二

参考文献

《算法设计》第6章动态规划 Jon Kleinberg ,Eva Tardos清华大学出版社

《动态规划》ppt            姜海涛

附录

求最大权值部分实现代码

参考姚光超博主的代码实现

constintMAX_N=100000;

//输入

intN,S[MAX_N],T[MAX_N];

 

//用于对工作排序的pair数组

pair<int,int>itv[MAX_N];

 

voidsolve()

{

   //pair进行的是字典序比较,为了让结束时间早的工作排在前面,把T存入first//S存入second

   for(inti=0;i<N;i++)

   {

            itv[i].first=T[i];

            itv[i].second=S[i];

   }

 

   sort(itv,itv+N);

 

   dp[0]=(itv[0].first-itv[0].second)*V[0];

   for(inti=1;i<N;i++)

   {

            intmax;

 

            //select the ithinterval

            intnonOverlap=lower_bound(itv,itv[i].second)-1;

            if(nonOverlap>=0)

                   max=dp[nonOverlap]+(itv[i].first-itv[i].second)*V[i];

            else

                   max=(itv[i].first-itv[i].second)*V[i];

 

            //do not selectthe ith interval

            dp[i]=max>dp[i-1]?max:dp[i-1];

   }

   printf(%d\n,dp[N-1]);

}