演算法導論16.1 活動選擇問題

sushauai發表於2015-12-22

這篇文章主要講述一個經典問題:活動選擇問題。並給出該問題的貪心演算法實現和動態規劃實現。

對於該問題的描述,在演算法導論第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 stub
		ActivitySelector 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 4
2 3 5
3 0 6
4 5 7
5 3 8
6 5 9
7 6 10
8 8 11
9 8 12
10 2 13
11 12 14
活動選擇情況如下:
id=1 start=1 end=4
id=4 start=5 end=7
id=8 start=8 end=11
id=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 stub
		ActivitySelectorDP 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 4
2 3 5
3 0 6
4 5 7
5 3 8
6 5 9
7 6 10
8 8 11
9 8 12
10 2 13
11 12 14
活動選擇情況如下:
id=1 start=1 end=4
id=4 start=5 end=7
id=8 start=8 end=11
id=11 start=12 end=14

相關文章