1. 问题描述:
Description
You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn.
Write a program that:
reads the number of intervals, their end points and integers c1, ..., cn from the standard input,
computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,...,n,
writes the answer to the standard output.
Input
The first line of the input contains an integer n (1 <= n <= 50000) -- the number of intervals. The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.
Output
The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i=1,2,...,n.
Sample Input
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
Sample Output
6
问题的大概意思是:给定一个闭区间,并且这个闭区间上的点都是整数,现在要求你使用最少的点来覆盖这些区间并且每个区间的覆盖的点的数量满足输入的要求点覆盖区间的数量,其中在这个区间的某些区间上要求要有特定的点来覆盖,
输入:
第一行输入的是测试样例的个数
接下来的是每个测试样例输入,其中包括区间的开始端点与结束端点,覆盖整个区间的点的数量,开始端点与结束端点都在50000之内,而且要求点的覆盖的数量在开始区间与结束区间之间
2. 这个问题是来自于POJ1201的一道题目,是区间选点问题的一种变体,但是我们对于区间选点问题清楚之后那么这种题目也是一样解决的,只不过需要在某些地方特别处理一下
这道题目跟区间调度的问题非常类似,我们也可以采用区间调度问题的策略运用到这道题目上面,尽量往结束时间的端点来选点因为这样做我们可以使尽量少的点覆盖更多的区间,之后就是选点的问题了,当我们选择了这个点之后需要标记一下,定义一个数轴来记录其中标记过的点,以防下一次在选点的时候重复选择。
而且在for循环中依次扫描这些给定的区间,看这个区间需要覆盖的点的数量是多少(有可能这个区间的标记的点出现在另外的区间上那么这个时候我们就选择跳过这个点)
3. 具体的代码如下:
import java.util.Arrays;
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
Interval intervals[] = new Interval[n];
for(int i = 0; i < n; i++){
intervals[i] = new Interval(sc.nextInt(), sc.nextInt(), sc.nextInt());
}
Arrays.sort(intervals);
//定义长度为最后结束时间的长度的数轴
int arrayLen = intervals[n - 1].t;
int axis[] = new int[arrayLen + 1];
for(int i = 0; i < n; i++){
//遍历每一个区间
int s = intervals[i].s;
int t = intervals[i].t;
int c = intervals[i].c;
int cnt = sum(axis, s, t);
//需要新增的点的数量:减去原来数轴上已经存在的点的数量
c -= cnt;
//System.out.println("c = " + c);
while(c > 0){
if(axis[t] == 0){
axis[t--] = 1;
c--;
}else{
t--;
}
}
}
int res = sum(axis, 0, arrayLen);
System.out.println(res);
sc.close();
}
private static int sum(int[] axis, int s, int t){
int cnt = 0;
for(int i = s; i <= t; i++){
if(axis[i] != 0){
cnt++;
}
}
return cnt;
}
private static class Interval implements Comparable<Interval>{
//自定义排序规则
int s;
int t;
int c;
public Interval(int s, int t, int c) {
this.s = s;
this.t = t;
this.c = c;
}
@Override
public int compareTo(Interval other) {
int x = this.t - other.t;
if(x == 0){
return this.s - other.s;
}else{
return x;
}
}
}
}
提交到POJ上会发生超时,但是代码的逻辑是没有什么问题的,关键是在扫描每个区间的时候消耗的时间比较多导致了超时,但是我们可以使用另外的一种数据结构来解决那就是树状数组,降低扫描区间的时间复杂度
其中涉及到开始时间和结束时间都需要排序的问题,这里我们采用了新建一个私有的内部类的方法把属性绑定在一起实现Compare接口然后自定义排序规则使用Arrays.sort()方法进行排序那么排序之后的开始时间和结束时间也是绑定在一起的,这样就不会乱了