一、问题
公司现在有8个任务,任务1-8的薪水分别是:5、1、8、4、6、3、2、4,有些任务之间是有时间冲突的,比如选了任务8就不能选任务6和7,而选了任务5就不能选任务1、2、3、4、6、7。如图,横轴代表时间,灰色矩形代表每个任务,矩形开始和结束的横坐标分别对应每个任务的开始和结束时间,红色数字代表薪水。比如任务1开始时间是1,结束时间是4,持续了(4-1)即3小时,薪水为5。现在的问题是,如何在0-11点之间,从这8个任务中选择时间互不冲突的若干个任务,使得得到的总薪水最大。
二、分析最优子结构、重叠子问题
用OPT(i)代表考虑第1至第i个任务时的最优解,比如OPT(5)代表考虑前5个任务的最优解,OPT(8)代表考虑前8个任务的最优解,考虑这个问题最关键的就是,分析每个任务选和不选的两种情况。现在由上图可知,选了任务8就不能选任务6和7,而任务8也可以不选,所以,当考虑OPT(8)时我们要考虑:
(1)如果选了任务8,任务6和7就不能选,那么只要再考虑前5个任务的最优解,即OPT(5);
(2)如果不选任务8,那只要考虑前7个任务的最优解,即OPT(7),就可以了;
(3)最后,我们比较上面两种情况得到的薪水,由薪水大小决定究竟选不选任务8
故OPT(8)=max{OPT(5)+4,OPT(7)},这里的4是指任务8的薪水,由上图可知是4
最后推出递归式:
上式,OPT(i)代表考虑前i个任务的最优解(1≤i≤8),Vi代表第i个任务的薪水,prev(i)是一个数组,标记如果选择了第i个任务,则剩余只要考虑前几个任务就可以了,比如prev(8)=5,如果选了第8个任务,只要考虑前5个就可以了;prev(6)=2,如果选了第6个任务,只要考虑前2个就可以了;
根据这个问题,我们可以得到Vi表:
V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 |
5 | 1 | 8 | 4 | 6 | 3 | 2 | 4 |
prev(i)表:
prev(1) | prev(2) | prev(3) | prev(4) | prev(5) | prev(6) | prev(7) | prev(8) |
0 | 0 | 0 | 1 | 0 | 2 | 3 | 5 |
最终由递推式计算得到OPT(i)表,注意初始时OPT(0)=0,而OPT(8)就是我们要的最终解:
OPT(0) | OPT(1) | OPT(2) | OPT(3) | OPT(4) | OPT(5) | OPT(6) | OPT(7) | OPT(8) |
0 | 5 | 5 | 8 | 9 | 9 | 9 | 10 | 13 |
上表中,比如OPT(3)代表如果只考虑前3个任务能得到的最大薪水,由于
OPT(3)=max{OPT(0)+8,OPT(2)}
而OPT(0)+8=8,OPT(2)已经计算好,为5,那么OPT(0)+8 > OPT(2),(注:
OPT(2)是怎么来的: 计算OPT(2)=max{OPT(0)+1,OPT(1)} 得到 OPT(0)+1 < OPT(1)
由于OPT(1)大所以要考虑OPT(1)是怎么来的: OPT(1)=max{OPT(0)+5,OPT(0)}=OPT(0)+5=5
)
可见如果只考虑前3个任务,我们选做任务集合为{3}时,就能得到最大薪水,为8
其他以此类推。
所以,最终能得到的最大薪水为OPT(8)=13。