试题D:矩形总面积
【问题描述】
平面上有个两个矩形 R 1 和 R 2 ,它们各边都与坐标轴平行。设 ( x 1 , y 1 ) 和
( x 2 , y 2 ) 依次是 R 1 的左下角和右上角坐标, ( x 3 , y 3 ) 和 ( x 4 , y 4 ) 依次是 R 2 的左下
角和右上角坐标,请你计算 R 1 和 R 2 的总面积是多少?
注意:如果 R 1 和 R 2 有重叠区域,重叠区域的面积只计算一次。
【输入格式】
输入只有一行,包含 8 个整数,依次是: x 1 , y 1 , x 2 , y 2 , x 3 , y 3 , x 4 和 y 4 。
【输出格式】
一个整数,代表答案。
【样例输入】
2 1 7 4 5 3 8 6
【样例输出】
22【评测用例规模与约定】
对于 20 % 的数据, R 1 和 R 2 没有重叠区域。
对于 20 % 的数据,其中一个矩形完全在另一个矩形内部。
对于 50 % 的数据,所有坐标的取值范围是 [0 , 10 ^3 ] 。
对于 100 % 的数据,所有坐标的取值范围是 [0 , 10^ 5 ] 。【样例说明】
样例中的两个矩形如图所示:
分析:
本题难点在于两个矩形部分重合的情况,我在比赛时是分三种情况讨论的(无重合,完全重合,部分重合)。
先将两个矩形需要占的最大板块的左下角与右上角找出来,然后依次遍历这个板块被占领的地区。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int x1 = scanner.nextInt(), y1 = scanner.nextInt();
int x2 = scanner.nextInt(), y2 = scanner.nextInt();
int x3 = scanner.nextInt(), y3 = scanner.nextInt();
int x4 = scanner.nextInt(), y4 = scanner.nextInt();
// 计算面积并且减去重叠部分的面积
long area = (long)(x2 - x1) * (y2 - y1) + (long)(x4 - x3) * (y4 - y3);
int overlapWidth = Math.max(0, Math.min(x2, x4) - Math.max(x1, x3)); // 重叠部分宽度
int overlapHeight = Math.max(0, Math.min(y2, y4) - Math.max(y1, y3)); // 重叠部分高度
if (overlapWidth > 0 && overlapHeight > 0) { // 存在重叠部分
area -= (long)overlapWidth * overlapHeight;
}
System.out.println(area);
}
}
试题G:买二赠一
题目描述
某商场有 N 件商品,其中第 i 件的价格是 Ai。现在该商场正在进行 “买二赠一” 的优惠活动,具体规则是:
每购买 2 件商品,假设其中较便宜的价格是 P(如果两件商品价格一样,则 P 等于其中一件商品的价格),就可以从剩余商品中任选一件价格不超过 P/2的商品,免费获得这一件商品。可以通过反复购买 2 件商品来获得多件免费商品,但是每件商品只能被购买或免费获得一次。
小明想知道如果要拿下所有商品(包含购买和免费获得),至少要花费多少钱?
输入格式
第一行包含一个整数 N。
第二行包含 N 个整数,代表 A1, A2, A3, . . . ,AN。
输出格式
输出一个整数,代表答案。
样例输入
7 1 4 2 8 5 7 1样例输出
25提示
小明可以先购买价格 4 和 8 的商品,免费获得一件价格为 1 的商品;再后买价格为 5 和 7 的商品,免费获得价格为 2 的商品;最后单独购买剩下的一件价格为 1 的商品。总计花费 4 + 8 + 5 + 7 + 1 = 25。不存在花费更低的方案。
对于 30% 的数据,1 ≤ N ≤ 20。
对于 100% 的数据,1 ≤ N ≤ 5 × 105,1 ≤ Ai ≤ 109
解题思路:
贪心+排序
首先排序,每次循环将两个最大的商品可以免费的价格用队列存放,然后判断数量低于免费的就可以直接免费掉。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] a = new int[n + 1];
for(int i = 1; i <= n; i++){
a[i] = scan.nextInt();
}
Arrays.sort(a); // 升序排序
Queue queue = new LinkedList<>(); // 存放免费机会
long res = 0;
while (n > 0){
while (!queue.isEmpty() && n > 0){
if(queue.peek() >= a[n]){ // 取出最大免费机会比较可以免费则指针向后并删除当前免费机会
queue.poll();
n--;
}else {
break; // 否则退出
}
}
if(n > 0) {
res += a[n];
n--;
}
while (!queue.isEmpty() && n > 0){
if(queue.peek() >= a[n]){ // 取出最大免费机会比较可以免费则指针向后并删除当前免费机会
queue.poll();
n--;
}else {
break; // 否则退出
}
}
if(n > 0) { // 防止越界,并取买的两个数中最小的价值的一半添加到免费机会
res += a[n];
queue.offer(a[n] / 2.0);
n--;
}
}
System.out.println(res);
}
}
最后希望正在看这篇文章的uu们蓝桥杯(或其他算法竞赛)都能取得好成绩!
如有错误或改进方案,欢迎评论区讨论指正。