贪心算法----区间选点问题(POJ1201)
题目:

题目的大致意思是,给定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)的更多相关文章
- UVa 1615 Highway (贪心,区间选点问题)
题意:给定一个数 n 个点,和一个d,要求在x轴上选出尽量少的点,使得对于给定的每个点,都有一个选出的点离它的欧几里德距离不超过d. 析:首先这是一个贪心的题目,并且是区间选点问题,什么是区间选点呢, ...
- UVA-1615 Highway (贪心,区间选点)
题目大意:有一条沿x轴正方向,长为L的高速公路,n个村庄,要求修建最少的公路出口数目,使得每个村庄到出口的距离不大于D. 题目分析:区间选点问题.在x轴上,到每个村庄距离为D的点有两个(超出范围除外) ...
- 贪心算法----区间覆盖问题(POJ2376)
题目: 题目的大概意思是约翰这个农民有N条牛,这些牛可以在一天中的某个时间段可以进行工作,他想把这个时间段分成若干个片段让这些牛去进行打扫任务,你的任务是安排尽量少的牛然后可以完成分成这些片段的打扫任 ...
- POJ1328 Radar Installation 【贪心·区间选点】
Radar Installation Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 54593 Accepted: 12 ...
- 【uva 1615】Highway(算法效率--贪心 区间选点问题)
题意:给定平面上N个点和一个值D,要求在x轴上选出尽量少的点,使得对于给定的每个店,都有一个选出的点离它的欧几里德距离不超过D. 解法:先把问题转换成模型,把对平面的点满足条件的点在x轴的直线上可得到 ...
- 基于贪心算法的几类区间覆盖问题 nyoj 12喷水装置(二) nyoj 14会场安排问题
1)区间完全覆盖问题 问题描述:给定一个长度为m的区间,再给出n条线段的起点和终点(注意这里是闭区间),求最少使用多少条线段可以将整个区间完全覆盖 样例: 区间长度8,可选的覆盖线段[2,6],[1, ...
- 【贪心算法】POJ-1328 区间问题
一.题目 Description Assume the coasting is an infinite straight line. Land is in one side of coasting, ...
- POJ 1328 Radar Installation 【贪心 区间选点】
解题思路:给出n个岛屿,n个岛屿的坐标分别为(a1,b1),(a2,b2)-----(an,bn),雷达的覆盖半径为r 求所有的岛屿都被覆盖所需要的最少的雷达数目. 首先将岛屿坐标进行处理,因为雷达的 ...
- 【贪心算法】POJ-2376 区间问题
一.题目 Description Farmer John is assigning some of his N (1 <= N <= 25,000) cows to do some cle ...
随机推荐
- Windows安装redis并将redis设置成服务
Redis 作为一种缓存工具,主要用于解决高并发的问题,在分布式系统中有着极其广泛的应用,Redis 本身是应用于 Linux/Unix 平台的(部署在服务器上边),官方并没有提供 Windows 平 ...
- centos/redhat/ubuntu不同之处
前言:最近用久了ubuntu,发现这个和centos还是有很大差别的,以下是我的个人总结: centos/redhat/ubuntu不同之处: 1.关系理解:centos和redhat,你可以理解为是 ...
- 末学者笔记--Linux权限管理
一.权限概述 Linux系统一般将文件可存/取访问的身份分为3个类别:owner(拥有者).group(和所有者同组的用户).others(其他人,除了所有者,除了同组的用户以及除了超级管理员),且3 ...
- Kafka文件存储机制及partition和offset
转载自: https://yq.aliyun.com/ziliao/65771 参考: Kafka集群partition replication默认自动分配分析 如何为kafka选择合适的p ...
- redis的两种安装方法
原:https://www.cnblogs.com/caokai520/p/4409712.html C# Redis 概念 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦 ...
- 维护爬虫代理IP池--采集并验证
任务分析 我们爬的免费代理来自于https://www.kuaidaili.com这个网站.用`requests`将ip地址与端口采集过来,将`IP`与`PORT`组合成`requests`需要的代理 ...
- Adams命令
1. FIND_MACRO_FROM_COMMAND(STRING): 通过宏命令找到宏所在位置 2. DEFAULT_GROUND($_topgui.model): 获取默认地面Part 3. DB ...
- datatable中的copy和clone的用法区分
dt.copy();//复制结构和数据 dt.clone();//仅复制结构,不复制数据
- 英语词汇—V01
今日词汇 1, wash [wɒʃ] n. 洗涤:洗的衣服:化妆水:冲积物 vt. 洗涤:洗刷:冲走:拍打 vi. 洗澡:被冲蚀 2, dust [dʌst] n. 灰尘:尘埃:尘土 vt. 撒:拂去 ...
- 学习使用Mendeley1
原文来自:https://www.mendeley.com/guides/desktop/01-desktop-interface 1.添加文件菜单 - 使用此功能将新条目添加到您的Mendeley库 ...