這篇文章主要講述一個經典問題:作用選取範圍問題。並給出該問題的貪心演算法實現和動態規劃實現。
對於該問題的描述,在演算法導論第16章給出了詳細的講解,這裡就不做解釋說明了,下面給出貪心演算法的Java語言實現:
package chapter1.homework1;import java.util.*;public class ActivitySelector {private int activitiesNum=0;//活動總數private Activity[] activities=null;//記錄所有活動,包括虛擬活動public static void main(String[] args) {// TODO Auto-generated method stubActivitySelector sample=new ActivitySelector();sample.getInputInfo();System.out.println("作用選取範圍結果:");sample.greedyActivitySelector();}public void greedyActivitySelector(){int i=0;for(int m=1;m<=this.activitiesNum;m++){if(this.activities[m].start>=this.activities[i].end){System.out.println("id="+this.activities[m].id+" start="+this.activities[m].start+" end="+this.activities[m].end);i=m;}}}public void getInputInfo(){System.out.println("請輸入活動的總數");Scanner in=new Scanner(System.in);this.activitiesNum=in.nextInt();System.out.println("請依次輸入活動的序號,活動的起始時間和活動的截止時間");activities=new Activity[this.activitiesNum+1];int id,start,end;activities[0]=new Activity(0,0,0);for(int i=1;i<this.activitiesNum+1;i++){id=in.nextInt();start=in.nextInt();end=in.nextInt();activities[i]=new Activity(id,start,end);}}public class Activity{private int id;private int start;private int end;public int getId() {return id;}public int getStart() {return start;}public int getEnd() {return end;}public Activity(int id,int start,int end){this.id=id;this.start=start;this.end=end;}}}
上述代碼是按照演算法導論書中GREEDY-ACTIVITY-SELECTOR(s,f)虛擬碼實現的,大家可以參考下,運行結果如下所示:
請輸入活動的總數11請依次輸入活動的序號,活動的起始時間和活動的截止時間1 1 42 3 53 0 64 5 75 3 86 5 97 6 108 8 119 8 1210 2 1311 12 14作用選取範圍情況如下:id=1 start=1 end=4id=4 start=5 end=7id=8 start=8 end=11id=11 start=12 end=14
在課後練習題16.1-1中,要求給出作用選取範圍問題的動態規划算法,下面就給出動態規劃的演算法。
在動態規划算法中,我們要利用到書中公式16.3,並且要定義數組c[i][j]來儲存在活動ai之後,活動aj之前的最大活動子集的數目。
演算法實現如下所示:
package chapter1.homework1;import java.util.Scanner;public class ActivitySelectorDP {private int activitiesNum=0;//活動總數private Activity[] activities=null;//記錄所有活動,包括虛擬活動private int c[][]=null;//定義數組儲存public static void main(String[] args) {// TODO Auto-generated method stubActivitySelectorDP sample=new ActivitySelectorDP();sample.getInputInfo();sample.dynamicProgramming();System.out.println("作用選取範圍情況如下:");sample.printSelectedActivity(0, sample.activitiesNum+1);}public void getInputInfo(){System.out.println("請輸入活動的總數");Scanner in=new Scanner(System.in);this.activitiesNum=in.nextInt();System.out.println("請依次輸入活動的序號,活動的起始時間和活動的截止時間");activities=new Activity[this.activitiesNum+2];int id,start,end;activities[0]=new Activity(0,0,0);for(int i=1;i<this.activitiesNum+1;i++){id=in.nextInt();start=in.nextInt();end=in.nextInt();activities[i]=new Activity(id,start,end);}activities[this.activitiesNum+1]=new Activity(this.activitiesNum+1,Integer.MAX_VALUE,Integer.MAX_VALUE);}public void dynamicProgramming(){this.c=new int[this.activitiesNum+2][this.activitiesNum+2];for(int i=0;i<=this.activitiesNum;i++){c[i][i+1]=0;}for(int step=2;step<=this.activitiesNum+1;step++){for(int i=0;i<=this.activitiesNum;i++){int j=i+step;if(j<this.activitiesNum+2){if(this.activities[i].end<=this.activities[j].start){int max=0;for(int k=i+1;k<j;k++){if(this.activities[k].start>=this.activities[i].end&&this.activities[k].end<=this.activities[j].start){int temp=c[i][k]+c[k][j]+1;if(temp>max)max=temp;}}if(max>c[i][j]){c[i][j]=max;}}}}}}public void printSelectedActivity(int start,int end){if(end-start==1){return;}for(int k=start+1;k<end;k++){if(this.activities[k].start>=this.activities[start].end&&this.activities[k].end<=this.activities[end].start){if(c[start][k]+c[k][end]+1==c[start][end]){printSelectedActivity(start,k);System.out.println("id="+k+" start="+this.activities[k].start+" end="+this.activities[k].end);printSelectedActivity(k,end);break;}}}}public class Activity{private int id;private int start;private int end;public int getId() {return id;}public int getStart() {return start;}public int getEnd() {return end;}public Activity(int id,int start,int end){this.id=id;this.start=start;this.end=end;}}}
程式運行結果如下所示:
請輸入活動的總數11請依次輸入活動的序號,活動的起始時間和活動的截止時間1 1 42 3 53 0 64 5 75 3 86 5 97 6 108 8 119 8 1210 2 1311 12 14作用選取範圍情況如下:id=1 start=1 end=4id=4 start=5 end=7id=8 start=8 end=11id=11 start=12 end=14