Expm 7_2区间调度问题

 

【问题描述】

给定n个活动,其中的每个活动ai包含一个起始时间si与结束时间fi。设计与实现算法从n个活动中找出一个最大的相互兼容的活动子集S。

要求:分别设计动态规划与贪心算法求解该问题。其中,对贪心算法分别给出递归与迭代两个版本的实现。

 

动态规划版本描述:

下面我们再换个角度考虑上面的问题。很多最优化深搜问题都可以巧妙地转化成动态规划问题,可以转化的根本原因在于存在重复子问题,我们看图四就会发现最多区间调度问题也存在重复子问题,所以可以利用动态规划来解决。假设区间已经排序,可以尝试这样设计递归式:前i个区间的最多不重叠区间个数为dp[i]。dp[i]等于啥呢?我们需要根据第i个区间是否选择这两种情况来考虑。如果我们选择第i个区间,它可能和前面的区间重叠,我们需要找到不重叠的位置k,然后计算最多不重叠区间个数dp[k]+1(如果区间按照开始时间排序,则前i+1个区间没有明确的分界线,我们必须按照结束时间排序);如果我们不选择第i个区间,我们需要从前i-1个结果中选择一个最大的dp[j];最后选择dp[k]+1和dp[j]中较大的。

选择或者不选择第i个区间都需要去查找其他的区间,顺序查找的复杂度为O(n),总共有n个区间,每个区间都需要查找,所以动态规划部分最初的算法复杂度为O(n2),已经从指数级降到多项式级,但是经过后面的优化还可以降到O(n),我们一步步来优化。

可以看出dp[i]是非递减的,这可以通过数学归纳法证明。也即当我们已经求得前i个区间的最多不重叠区间个数之后,再求第i+1个区间时,我们完全可以不选择第i+1个区间,从而使得前i+1个区间的结果和前i个区间的结果相同;或者我们选择第i+1个区间,在不重叠的情况下有可能获得更优的结果。dp[i]是非递减的对我们有什么意义呢?首先,如果我们在计算dp[i]时不选择第i个区间,则我们就无需遍历前i-1个区间,直接选择dp[i-1]即可,因为它是前i-1个结果中最大的(虽然不一定是唯一的),此时伪代码中的dp[j]就变成了dp[i-1]。其次,在寻找和第i个区间不重叠的区间时,我们可以避免顺序遍历。如果我们将dp[i]的值列出来,肯定是这样的:

1,1,…,1,2,2,…,2,3,3,…,3,4……

即dp[i]的值从1开始,顺次递增,每一个值的个数不固定。dp[0]肯定等于1,后面几个区间如果和第0个区间重叠,则的dp值也为1;当出现一个区间不和第0个区间重叠时,其dp值变为2,依次类推。由此我们可以得到一个快速获得不重叠位置的方法:重新开辟一个新的数组,用来保存每一个不同dp值的最开始位置,例如pos[1]=0,pos[2]=3,…。这样我们就可以利用O(1)的时间实现find_nonoverlap_pos函数了,然后整个动态规划算法的复杂度就降为O(n)了。

其实从dp的值我们已经就可以发现一些端倪了:dp值发生变化的位置恰是出现不重叠的位置!再仔细思考一下就会出现一开始提到的贪心算法了。所以可以说,贪心算法是动态规划算法在某些问题中的一个特例。该问题的特殊性在于只考虑区间的个数,也即每次都是加1的操作,后面会看到,如果变成考虑区间的长度,则贪心算法不再适用。

 1 package org.xiu68.exp.exp7;
 2 
 3 public class Task{
 4     public int startTime;    //开始时间
 5     public int endTime;        //结束时间
 6     
 7     public Task(int startTime,int endTime){
 8         this.startTime=startTime;
 9         this.endTime=endTime;
10     }
11 }
View Code

 

 1 package org.xiu68.exp.exp7;
 2 
 3 import java.util.ArrayList;
 4 
 5 public class Exp7_2_1 {
 6     public static void main(String[] args) {
 7         // TODO Auto-generated method stub
 8         ArrayList<Task> tasks=new ArrayList<>();
 9         tasks.add(new Task(1,5));
10         tasks.add(new Task(2,4));
11         tasks.add(new Task(3,6));
12         tasks.add(new Task(5,8));
13         intervalSchedule(tasks);
14     }
15 
16     public static void intervalSchedule(ArrayList<Task> tasks){
17         //按结束时间从小到大进行排序
18         tasks.sort((t1,t2)->{
19             if(t1.endTime<=t2.endTime)
20                 return -1;
21             else
22                 return 1;
23         });
24         
25         Task[] t = new Task[tasks.size()];
26         tasks.toArray(t);
27         int result = 0;
28         if(t.length>=1){
29             result=1+intervalRecuisive(t, 0, t.length-1);
30         }
31         System.out.println("最大区间个数为: "+result);
32     }
33     public static int intervalRecuisive(Task[] task,int i,int j){
34         int m=i+1;
35         //下一个任务与前面的任务不兼容
36         while(m<=j && task[m].startTime<task[i].endTime)
37             m++;
38         //已经没有任务与前面任务兼容
39         if(m<=j)
40             return 1+intervalRecuisive(task, m, j);
41         else
42             return 0;
43     }
44 }
View Code

 

 1 package org.xiu68.exp.exp7;
 2 
 3 import java.util.ArrayList;
 4 
 5 public class Exp7_2_2 {
 6 
 7     //区间调度的迭代版本(最大区间个数)
 8     public static void main(String[] args) {
 9         // TODO Auto-generated method stub
10         ArrayList<Task> tasks=new ArrayList<>();
11         tasks.add(new Task(6,9));
12         tasks.add(new Task(6,7));
13         tasks.add(new Task(5,6));
14         tasks.add(new Task(4,5));
15         intervalSchedule(tasks);
16     }
17     
18     public static void intervalSchedule(ArrayList<Task> tasks){
19         //按结束时间从小到大进行排序
20         tasks.sort((t1,t2)->{
21             if(t1.endTime<=t2.endTime)
22                 return -1;
23             else
24                 return 1;
25         });
26         
27         int result=0,end=0;
28         for(int i=0;i<tasks.size();i++){        //每次选择结束时间最早的任务
29             if(tasks.get(i).startTime>=end){        //如果任务之间相互兼容
30                 result+=1;
31                 end=tasks.get(i).endTime;
32             }
33         }
34         System.out.println("最大区间个数为: "+result);
35     }
36 }
View Code

 

posted @ 2017-12-05 17:55  清风☆薰衣草  阅读(304)  评论(0编辑  收藏  举报