算法导论16.1 活动选择问题

这篇文章主要讲述一个经典问题:活动选择问题。并给出该问题的贪心算法实现和动态规划实现。

对于该问题的描述,在算法导论第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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值