题目:

  

  题目的大致意思是,给定n个闭区间,并且这个闭区间上的点都是整数,现在要求你使用最少的点来覆盖这些区间并且每个区间的覆盖的点的数量满足输入的要求点覆盖区间的数量。

  输入:

    第一行输入n,代表n个区间。

    接下来的n行每行的第一个数代表区间起点,第二个数代表区间终点,第三个数代表这个区间必须要选取的点的数量。

  输出:

    输出最少的点的数量,这些最少的点要覆盖全部区间。

  这个题是区间选点问题的一种变体,但是我们对于区间选点问题清楚之后那么这种题目也是一样解决的,只不过需要在某些地方特别处理一下。这道题目跟区间调度的问题非常类似,我们也可以采用区间调度问题的策略运用到这道题目上面,尽量往结束时间的端点来选点因为这样做我们可以使尽量少的点覆盖更多的区间,之后就是选点的问题了,当我们选择了这个点之后需要标记一下,定义一个数轴来记录其中标记过的点,以防下一次在选点的时候重复选择。而且在for循环中依次扫描这些给定的区间,看这个区间需要覆盖的点的数量是多少(有可能这个区间的标记的点出现在另外的区间上那么这个时候我们就选择跳过这个点)

  代码:

 import java.util.Arrays;
import java.util.Scanner; public class 区间选点问题1 {
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 max = intervals[n - 1].t;// 右端最大值
int[] axis = new int[max + 1];// 标记数轴上的点是否已经被选中
// int[] sums = new int[max + 1];
for (int i = 0; i < n; i++) {
// 1.查阅区间中有多少个点
int s = intervals[i].s;// 起点
int t = intervals[i].t;// 终点
int cnt = sum(axis, s, t);// 找到这个区间已经选点的数量,
//sums[t] - sums[s - 1]; 效率低
// 2.如果不够,从区间右端开始标记,遇标记过的就跳过
intervals[i].c -= cnt;// 需要新增的点的数量
while (intervals[i].c > 0) {
if (axis[t] == 0) {// 从区间终点开始选点
axis[t] = 1;
// updateSums(t,sums);//更新前缀和
intervals[i].c--;// 进一步减少需要新增的点的数量
t--;
} else {// 这个点已经被选过了
t--;
}
} }
System.out.println(sum(axis, 0, max));
} /**
* 统计数轴axis上s-t区间已经有多少个点被选中
*
* @param axis
* @param s
* @param t
* @return
*/
private static int sum(int[] axis, int s, int t) {
int sum = 0;
for (int i = s; i <= t; i++) {
sum += axis[i];
}
return sum;
} private static void updateSums(int t, int[] sums) {
for (int i = t; i < sums.length; i++) {
sums[i]++;
}
} 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;
}
}
}

  结果:

    

  但是上面这个代码提交到OJ上面会发生超时,代码逻辑本身没有什么问题,关键是在扫描每个区间的时候消耗的时间比较多导致了超时,但是我们可以使用另外的一种数据结构来解决,那就是树状数组,降低扫描区间的时间复杂度。关于树状数组现在不太懂,而且也脱离了贪心算法的范畴,现在把代码记录下来,留作以后再看。

  代码:

 import java.util.Arrays;
import java.util.Scanner; public class 区间选点问题2 {
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 max = intervals[n - 1].t;// 右端最大值
int[] axis = new int[max + 1];
int[] c = new int[max + 2];
// int[] sums = new int[max + 1];
for (int i = 0; i < n; i++) {
// 1.查阅区间中有多少个点
int s = intervals[i].s;// 起点
int t = intervals[i].t;// 终点
int cnt = sum(t + 1, c, max + 1) - sum(s, c, max + 1);// sum(axis,s,t);//sums[t]
// - sums[s
// -
// 1];//效率低
// 2.如果不够,从区间右端开始标记,遇标记过的就跳过
intervals[i].c -= cnt;
while (intervals[i].c > 0) {
if (axis[t] == 0) {
axis[t] = 1;
update(t + 1, 1, c, max + 1);
intervals[i].c--;
t--;
} else {
t--;
}
} }
System.out.println(sum(max + 2, c, max + 1));
} /**
* 更新树状数组c,注意i是项数,不是下标,而是下标+1
*/
private static void update(int i, int delta, int[] c, int n) {
for (; i <= n; i += lowbit(i)) {
c[i] += delta;
}
} /**
* 前i项和,注意:i不是下标
*
* @param i
* @return
*/
private static int sum(int i, int[] c, int n) {
int sum = 0;
if (i > n)
i = n;
for (; i > 0; i -= lowbit(i)) {
sum += c[i];
}
return sum;
} /**
* 它通过公式来得出k,其中k就是该值从末尾开始1的位置。 然后将其得出的结果加上x自身就可以得出当前节点的父亲节点的位置
* 或者是x减去其结果就可以得出上一个父亲节点的位置。
* 比如当前是6,二进制就是0110,k为2,那么6+2=8,C(8)则是C(6)的父亲节点的位置;
* 相反,6-2=4,则是C(6)的上一个父亲节点的位置。
*/
static int lowbit(int x) {
return x - (x & (x - 1));
} 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;
}
}
}

 

贪心算法----区间选点问题(POJ1201)的更多相关文章

  1. UVa 1615 Highway (贪心,区间选点问题)

    题意:给定一个数 n 个点,和一个d,要求在x轴上选出尽量少的点,使得对于给定的每个点,都有一个选出的点离它的欧几里德距离不超过d. 析:首先这是一个贪心的题目,并且是区间选点问题,什么是区间选点呢, ...

  2. UVA-1615 Highway (贪心,区间选点)

    题目大意:有一条沿x轴正方向,长为L的高速公路,n个村庄,要求修建最少的公路出口数目,使得每个村庄到出口的距离不大于D. 题目分析:区间选点问题.在x轴上,到每个村庄距离为D的点有两个(超出范围除外) ...

  3. 贪心算法----区间覆盖问题(POJ2376)

    题目: 题目的大概意思是约翰这个农民有N条牛,这些牛可以在一天中的某个时间段可以进行工作,他想把这个时间段分成若干个片段让这些牛去进行打扫任务,你的任务是安排尽量少的牛然后可以完成分成这些片段的打扫任 ...

  4. POJ1328 Radar Installation 【贪心&#183;区间选点】

    Radar Installation Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 54593   Accepted: 12 ...

  5. 【uva 1615】Highway(算法效率--贪心 区间选点问题)

    题意:给定平面上N个点和一个值D,要求在x轴上选出尽量少的点,使得对于给定的每个店,都有一个选出的点离它的欧几里德距离不超过D. 解法:先把问题转换成模型,把对平面的点满足条件的点在x轴的直线上可得到 ...

  6. 基于贪心算法的几类区间覆盖问题 nyoj 12喷水装置(二) nyoj 14会场安排问题

    1)区间完全覆盖问题 问题描述:给定一个长度为m的区间,再给出n条线段的起点和终点(注意这里是闭区间),求最少使用多少条线段可以将整个区间完全覆盖 样例: 区间长度8,可选的覆盖线段[2,6],[1, ...

  7. 【贪心算法】POJ-1328 区间问题

    一.题目 Description Assume the coasting is an infinite straight line. Land is in one side of coasting, ...

  8. POJ 1328 Radar Installation 【贪心 区间选点】

    解题思路:给出n个岛屿,n个岛屿的坐标分别为(a1,b1),(a2,b2)-----(an,bn),雷达的覆盖半径为r 求所有的岛屿都被覆盖所需要的最少的雷达数目. 首先将岛屿坐标进行处理,因为雷达的 ...

  9. 【贪心算法】POJ-2376 区间问题

    一.题目 Description Farmer John is assigning some of his N (1 <= N <= 25,000) cows to do some cle ...

随机推荐

  1. MySQL Percona server 5.5 安装审计插件

    近期,公司要求对MySQL 数据库上操作进行审计:通过了解MySQL 官方企业版(付费版)本中集成了audit_log审计插件,但是社区开源版本中并不包含该插件,也没提供下载.进一步了解 MariaD ...

  2. 【DOS】Win7系统文件夹名太长无法删除问题的解决

    一个测试工具产生了几个坑爹文件夹名为n个“x” ,系统提示删除不掉. 网上百度,说什么压缩.写bat文件...统统没用. 猛地看到右击菜单中安装了git客户端工具,想试试看.在该文件夹目录下Git B ...

  3. ThoughtWorks的面试总结

    今天有幸到ThoughtWorks去面试.我觉得自己的能力与他们的需要有些距离(还不知道面试结果如何). 逻辑测试部分,不是很难,是语言问题.几乎用了1个小时去理解一句表达.在Pair Program ...

  4. JAVA BigDecimal 用法

    一.BigDecimal 的加减乘除 BigDecimal bignum1 = new BigDecimal("10"); BigDecimal bignum2 = new Big ...

  5. js获取当前时间并实时刷新

    效果如图: 代码如下: <html> <head> <title>js获取当前时间并实时刷新</title> <script> //页面加载 ...

  6. spring boot+mybatis+quartz项目的搭建完整版

    1. 利用spring boot提供的工具(http://start.spring.io/)自动生成一个标准的spring boot项目架构 2. 因为这里我们是搭建spring boot+mybat ...

  7. Angular Material design设计

    官网: https://material.io/design/ https://meterial.io/components 优秀的Meterial design站点: http://material ...

  8. pip包导出

    用pip对已有的环境做导出准备 1. 使用pip导出当前环境所有依赖包信息文件 pip freeze > requirements.txt 2. 下载所有依赖包到本地 pip install - ...

  9. .NET英文技术文章导读(2017-03-23)

    关键字:VS2017.扩展.Service Fabric.Unit Test.ELMAH Web开发人员必装的5个VS2017扩展 作者:Jeffrey T. Fritz 链接:https://blo ...

  10. CentOs查看某个字符串在某个目录下的行数

    如果你想在当前目录下 查找"hello,world!"字符串,可以这样: grep -rn "hello,world!" ./ ./ : 表示路径为当前目录. ...