贪心法解决区间调度(不相交区间和区间选点)问题

不相交区间问题:
问题描述:
有n项工作,每项工作分别在si时间开始,ti时间结束。对于每项工作,你都可以选择是否参与,如果选择了参与,那么自始至终都必须全程参与。此外,参与工作的时间段不能重复(即使是开始的瞬间和结束的瞬间的重叠也是不允许的)。你的目标是参与尽可能多的工作,那么最多能参与多少项工作?

输入:
第一行:n
第二行:n个整数空格隔开,代表n个工作的开始时间
第三行:n个整数空格隔开,代表n个工作的结束时间

例样输入:
5
1 2 4 6 8
3 5 7 9 10

输出:
3

解题思路:
利用贪心法每一步选取最优的方案,已达到整体最优。想要尽可能参与多个工作,当完成一个工作后就要选取工作结束时间尽可能小的工作,并且下一个工作的开始时间一定要大于现在工作的结束时间。我们可以建立一个对象,将工作的开始时间和结束时间包含进对象中。然后将对象按照结束时间进行排序。然后按照排序后的结果依次选取工作,同时判断是否满足上一个工作的结束时间小于下一个工作的开始时间。

代码如下;

import java.util.*;

public class 不相交区间 {
	private static  class job implements Comparable<job>{
		public int s;
		public int t;
		job(int s, int t){
			this.s = s;
			this.t = t;
		}
		@Override
		public int compareTo(job other) {
			return this.t - other.t;
		}
	}
	
	public static void main(String[] args){
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt();
		int[] s = new int[n];
		int[] t = new int[n];
		for(int i=0; i<n; i++){
			s[i] = scanner.nextInt();
		}
		for(int i=0; i<n; i++){
			t[i] = scanner.nextInt();
		}
		job[] arr = new job[n];
		for(int i=0; i<n; i++){
			arr[i] = new job(s[i], t[i]);
		}
		Arrays.sort(arr);
		System.out.println(f(arr, n));
	}

	private static int f(job[] arr, int n) {
		int count = 1;
		int y = arr[0].t;//表示当前工作的结束时间
		for(int i=1; i<n; i++){
			if(arr[i].s>y){
				y = arr[i].t;
				count++;
			}
		}
		return count;
	}
	
}


区间选点问题:
问题描述:
给定多个区间,区间之间可能会发生部分重叠。在一个区间的范围内取一个点则这个区间就被称为被命中区间。要使得所有的区间都成为命中区间;问最少需要取多少个点?假定所有区间都是开区间。

输入:
第一行:n
第二行:n个整数空格隔开,代表n个区间的开始点
第三行:n个整数空格隔开,代表n个区间的结束点

输出:
一个整数,表示需要最少点的个数。

解题思路:
这个解题方法和区间调度的方法完全相同。首先将多出的区间按照先结束的排在前面进行排序。然后将排序后的区间一次取点,第一个区间直接去区间的结束点,之后的每一个区间取点之前都判断一下上一个取点是否在区间内。在则跳过此区间,不在则取这个区间的结束点。直到遍历完所有区间。总之取的每一个点都是区间的结束点。这样能保证发生覆盖的区间只取了一个点。

代码和上面相同。

你可能感兴趣的:(算法很美课程学习)