耍杂技的牛
农民约翰的N头奶牛(编号为1…N)计划逃跑并加入马戏团,为此它们决定练习表演杂技。
奶牛们不是非常有创意,只提出了一个杂技表演:
叠罗汉,表演时,奶牛们站在彼此的身上,形成一个高高的垂直堆叠。
奶牛们正在试图找到自己在这个堆叠中应该所处的位置顺序。
这N头奶牛中的每一头都有着自己的重量Wi以及自己的强壮程度Si。
一头牛支撑不住的可能性取决于它头上所有牛的总重量(不包括它自己)减去它的身体强壮程度的值,现在称该数值为风险值,风险值越大,这只牛撑不住的可能性越高。
您的任务是确定奶牛的排序,使得所有奶牛的风险值中的最大值尽可能的小。
输入格式
第一行输入整数N,表示奶牛数量。
接下来N行,每行输入两个整数,表示牛的重量和强壮程度,第i行表示第i头牛的重量Wi以及它的强壮程度Si。
输出格式
输出一个整数,表示最大风险值的最小可能值。
数据范围
1≤N≤50000,
1≤Wi≤10,000,
1≤Si≤1,000,000,000
输入样例:
3
10 3
2 5
3 3
输出样例:
2
代码:
import java.util.Arrays;
import java.util.Map;
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
Node[] nodes = new Node[n+5];
for(int i=0;i<n;i++){
int w = sc.nextInt();
int s = sc.nextInt();
nodes[i] = new Node(w,s);
}
Arrays.sort(nodes,0,n);
int sum = 0;
int res = Integer.MIN_VALUE;
for(int i=0;i<n;i++){
res = Math.max(res,sum-nodes[i].s);
sum += nodes[i].w;
}
System.out.println(res);
}
}
class Node implements Comparable<Node>{
int w,s,sum;
public Node(int w, int s) {
this.w = w;
this.s = s;
this.sum = w+s;
}
@Override
public int compareTo(Node o) {
return this.sum-o.sum;
}
}
区间选点
给定N个闭区间[ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。
输出选择的点的最小数量。
位于区间端点上的点也算作区间内。
输入格式
第一行包含整数N,表示区间数。
接下来N行,每行包含两个整数ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需的点的最小数量。
数据范围
1≤N≤105,
−109≤ai≤bi≤109
输入样例:
3
-1 1
2 4
3 5
输出样例:
2
思路:
按照区间左端点排序,每次判断当前区间是否包含在上次选择的dis以内。
如果不在,那么必然要在此区间中选择一个点,我们将dis赋值为当前区间的右端点。
如果在,为了确保每个区间都被选择过一个点。我们需要令dis = min(dis,nodes[i].r);这样可以确保所有的区间都被选择过一个点。
代码:
import java.util.Arrays;
import java.util.Scanner;
public class Main{
static int n;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
Node[] nodes = new Node[n+5];
for(int i=0;i<n;i++){
int a = sc.nextInt();
int b = sc.nextInt();
nodes[i] = new Node(a,b);
}
Arrays.sort(nodes,0,n);
int res = 0;
int dis = Integer.MIN_VALUE;
for(int i=0;i<n;i++){
if(nodes[i].l>dis) {
res++;
dis = nodes[i].r;
}else{
dis = Math.min(dis,nodes[i].r);
}
}
System.out.println(res);
}
}
class Node implements Comparable<Node>{
int l,r;
public Node(int l, int r) {
this.l = l;
this.r = r;
}
@Override
public int compareTo(Node o) {//按照左端点排序
return this.l-o.l;
}
}
最大不相交区间数量
给定N个闭区间[ai,bi],请你在数轴上选择若干区间,使得选中的区间之间互不相交(包括端点)。
输出可选取区间的最大数量。
输入格式
第一行包含整数N,表示区间数。
接下来N行,每行包含两个整数ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示可选取区间的最大数量。
数据范围
1≤N≤105,
−109≤ai≤bi≤109
输入样例:
3
-1 1
2 4
3 5
输出样例:
2
思路:
在n个区间中选择若干个互不相交的区间,我们可以将区间按照右端点排序,每次判断当前区间是否和dis有交点,没有交点时,我们选择当前区间。
代码:
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();
Node[] nodes = new Node[n+5];
for(int i=0;i<n;i++){
int a = sc.nextInt();
int b = sc.nextInt();
nodes[i] = new Node(a,b);
}
Arrays.sort(nodes,0,n);
int res = 0;
int dis = Integer.MIN_VALUE;
for(int i=0;i<n;i++){
if(dis<nodes[i].l){
res ++;
dis = nodes[i].r;
}
}
System.out.println(res);
}
}
class Node implements Comparable<Node>{
int l,r;
public Node(int l, int r) {
this.l = l;
this.r = r;
}
@Override
public int compareTo(Node o) {
return this.r-o.r;
}
}
区间分组
给定N个闭区间[ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。
输出最小组数。
输入格式
第一行包含整数N,表示区间数。
接下来N行,每行包含两个整数ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示最小组数。
数据范围
1≤N≤105,
−109≤ai≤bi≤109
输入样例:
3
-1 1
2 4
3 5
输出样例:
2
思路:
代码
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
Node[] nodes = new Node[n+5];
for(int i=0;i<n;i++){
int a = sc.nextInt();
int b = sc.nextInt();
nodes[i] = new Node(a,b);
}
Arrays.sort(nodes,0,n,new Ok());
PriorityQueue<Node> queue = new PriorityQueue<>();
for(int i=0;i<n;i++){
if(queue.size()==0||queue.peek().r>=nodes[i].l){
queue.add(nodes[i]);
}else{
queue.poll();
queue.add(nodes[i]);
}
}
System.out.println(queue.size());
}
}
class Ok implements Comparator<Node> {
@Override
public int compare(Node o1, Node o2) {
return o1.l-o2.l;
}
}
class Node implements Comparable<Node>{
int l,r;
public Node(int l, int r) {
this.l = l;
this.r = r;
}
@Override
public int compareTo(Node o) { //按照右端点排序
return this.r-o.r;
}
}
区间覆盖
给定N个闭区间[ai,bi]以及一个线段区间[s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。
输出最少区间数,如果无法完全覆盖则输出-1。
输入格式
第一行包含两个整数s和t,表示给定线段区间的两个端点。
第二行包含整数N,表示给定区间数。
接下来N行,每行包含两个整数ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需最少区间数。
如果无解,则输出-1。
数据范围
1≤N≤105,
−109≤ai≤bi≤109,
−109≤s≤t≤109
输入样例:
1 5
3
-1 3
2 4
3 5
输出样例:
2
代码:
import java.util.Arrays;
import java.util.Map;
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int s = sc.nextInt();
int t = sc.nextInt();
int n = sc.nextInt();
Node[] nodes = new Node[n+5];
for(int i=0;i<n;i++){
int a = sc.nextInt();
int b = sc.nextInt();
nodes[i] = new Node(a,b);
}
Arrays.sort(nodes,0,n);
int dis = s;
int res = 0;
for(int i=0;i<n;i++){
if(nodes[i].l>dis){
System.out.println("-1");
return;
}else{
res ++;
int temp = dis;
while(i<n&&nodes[i].l<=dis){
temp = Math.max(temp,nodes[i].r);
i++;
}
dis = temp;
i--;
}
if(dis>=t) break;
}
if(dis<t) System.out.println("-1");
else System.out.println(res);
}
}
class Node implements Comparable<Node>{
int l,r;
public Node(int l, int r) {
this.l = l;
this.r = r;
}
@Override
public int compareTo(Node o) {
return this.l-o.l;
}
}