矩形分割(二分答案)

题目

平面上有一个大矩形,其左下角坐标 (0,0),右上角坐标 (R,R)。大矩形内部包含一些小矩形,小矩形都平行于坐标轴且互不重叠。所有矩形的顶点都是整点。要求画一根平行于y轴的直线x=k( k 是整数),使得这些小矩形落在直线左边的面积必须大于等于落在右边的面积,且两边面积之差最小。并且,要使得大矩形在直线左边的的面积尽可能大。注意:若直线穿过一个小矩形,将会把它切成两个部分,分属左右两侧。

Input
第一行是整数 R,表示大矩形的右上角坐标是 (R,R)。
接下来的一行是整数 N,表示一共有 N个小矩形。
再接下来有N 行。每行有4个整数 L T W H
表示有一个小矩形的左上角坐标是 (L,T) ,宽度是W,高度是 H.
小矩形不会有位于大矩形之外的部分。

Output
输出整数 n ,表示答案应该是直线 x=n 。 如果必要的话,x=R 也可以是答案。

Sample Input 1
1000
2
1 1 2 1
5 1 2 1

Sample Output 1
5
Hint

1≤ R≤ 10^6
0<N≤ 10000
0≤L,T≤ R,0≤W,H≤ R
Time Limit
1000MS
Memory Limit
256MB

题意分析

这道题首先给出一个大矩形,在大矩形中有许多小矩形,大矩形的宽为R,要在(0,R)内找出一条分割线,保证在分割线左侧所有小矩形的面积和大于等于右侧所有小矩形的面积和,在分割线之间的矩形也算,还要保证左边所有小矩形面积和与右侧所有小矩形面积和之差最小,即(S左-S右)最小!最后在保证(S左-S右)最小的情况下,求得分割线横坐标x尽量大!

解题思路

首先暴力想法,从0开始枚举x,把所有满足题意的x记录下来,最后求最大x!
暴力思想可以满足小数据,但是R为10 ^ 6显然不可能暴力通过!

怎么办呢?

既然线性搜索不满足,那么想当然二分搜索啊!

我们先找一下这道题的单调关系

首先可以看到,随着x增大左侧所有小矩形面积也会增大,右侧所有小矩形面积会减小,所以S左-S右会随着x增大而增大!

有了单调关系我们套入二分答案的模板就可以,那么if()中的check函数怎么写呢?

我们需要求出左侧所有小矩形面积和,然后和所有小矩形面积和进行比较,
如果S左*2>=S总,证明x取大了,right=mid 如果小于x取小了,需要left=mid!

怎么做到在满足S左-S右最小,并且尽量使x大呢?

我们先看一副图片

在这里插入图片描述

从图片中我们可以看到,第一条分割线显然不是最优的,第二条分割线才是最优的!
我们只需要让x++,并且满足S左-S右的差值不变就可以,看x究竟能加到多少,就是要求的x最大值!

完整代码

#include<cstdio>//uncle-lu
#include<algorithm>
#include<iostream>
using namespace std;
struct node{
	/*
	 *  x : x坐标
	 *  y : y坐标
	 *  h : 高度
	 *  w : 宽度
	 */
	long long int x,y,h,w;
}a[10010];
long long int tot;
long long int r,n;

/* sum函数
 * 作用:
 *		统计分割线左边的面积和
 * 变量:
 *		x : 分割线
 *		sum_all : 分割线左边所有矩阵的和
 */
long long int sum(long long int x)
{
	long long int sum_all=0;
	for(int i=1;i<=n;++i)
	{
		if(a[i].x+a[i].w<=x)
		{
			sum_all+=a[i].h*a[i].w;
		}
		else if(a[i].x<x&&a[i].x+a[i].w>x)
		{
			sum_all+=a[i].h*(x-a[i].x);
		}
		else break;
	}
	return sum_all;
}


int main()
{
	scanf("%lld",&r);
	scanf("%lld",&n);
	for(int i=1;i<=n;++i)
	{
		scanf("%lld%lld%lld%lld",&a[i].x,&a[i].y,&a[i].w,&a[i].h);
		tot+=(a[i].h*a[i].w);
	}
	/*
	 * ans_mean : 记录答案分割线分割出的左区间大小
	 * ans : 记录答案分割线
	 */
	long long int left=0,right=r+1,mid;
	long long int ans_mean;
	long long int ans=0;
	while(left+1<right)
	{
		mid=(left+right)/2;
		long long int sum_left=sum(mid);
		if(sum_left*2>=tot)
		{
			ans_mean=sum_left;
			ans=mid;
			right=mid;
		}
		else left=mid;
	}
	/*
	 * while将分割线尽量往右移(处理存在空白空挡的部分)
	 */
	while(ans<r&&sum(ans+1)==ans_mean)ans++;
	printf("%lld\n",ans);
	return 0;
}

如果对你有帮助,多多点赞支持,感谢观看!

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
1. 算法的基本概念 利用计算机算法为计算机解题的过程实际上是在实施某种算法。 (1)算法的基本特征 算法一般具有4个基本特征:可行性、确定性、有穷性、拥有足够的情报。 (2)算法的基本运算和操作 算法的基本运算和操作包括:算术运算、逻辑运算、关系运算、数据传输。 (3)算法的3种基本控制结构 算法的3种基本控制结构是:顺序结构、选择结构、循环结构。 (4)算法基本设计方法 算法基本设计方法:列举法、归纳法、递推、递归、减半递推技术、回溯法。 (5)指令系统 所谓指令系统指的是一个计算机系统能执行的所有指令的集合。 (2)数据结构研究的3个方面 ① 数据集合中各数据元素之间所固有的逻辑关系,即数据的逻辑结构; ② 在对数据进行处理时,各数据元素在计算机中的存储关系,即数据的存储结构; ③ 对各种数据结构进行的运算。 2. 逻辑结构 数据的逻辑结构是对数据元素之间的逻辑关系的描述,它可以用一个数据元素的集合和定义在此集合中的若干关系来表示。数据的逻辑结构有个要素:一是数据元素的集合,通常记为D;二是D上的关系,它反映了数据元素之间的前后件关系,通常记为R。一个数据结构可以表示成:B=(D,R) 其中,B表示数据结构。为了反映D中各数据元素之间的前后件关系,一般用二元组来表示。 例如,如果把一年四季看作一个数据结构,则可表示成:B =(D,R) D ={春季,夏季,秋季,冬季} R ={(春季,夏季),(夏季,秋季),(秋季,冬季)} 3. 存储结构 数据的逻辑结构在计算机存储空间中的存放形式称为数据的存储结构(也称数据的物理结构)。 由于数据元素在计算机存储空间中的位置关系可能与逻辑关系不同,因此,为了表示存放在计算机存储空间中的各数据元素之间的逻辑关系(即前后件关系),在数据的存储结构中,不仅要存放各数据元素的信息,还需要存放各数据元素之间的前后件关系的信息。 一种数据的逻辑结构根据需要可以表示成多种存储结构,常用的存储结构有顺序、链接等存储结构。 顺序存储方式主要用于线性的数据结构,它把逻辑上相邻的数据元素存储在物理上相邻的存储单元里,结点之间的关系由存储单元的邻接关系来体现。 链式存储结构就是在每个结点中至少包含一个指针域,用指针来体现数据元素之间逻辑上的联系。 1.2.2 线性结构和非线性结构 根据数据结构中各数据元素之间前后件关系的复杂程度,一般将数据结构分为大类型:线性结构与非线性结构。 (1)如果一个非空的数据结构满足下列个条件: ① 有且只有一个根结点; ② 每一个结点最多有一个前件,也最多有一个后件。 则称该数据结构为线性结构。线性结构又称线性表。在一个线性结构中插入或删除任何一个结点后还应是线性结构。栈、队列、串等都为线性结构。 如果一个数据结构不是线性结构,则称之为非线性结构。数组、广义表、树和图等数据结构都是非线性结构。 (2)线性表的顺序存储结构具有以下个基本特点: ① 线性表中所有元素所占的存储空间是连续的; ② 线性表中各数据元素在存储空间中是按逻辑顺序依次存放的。 元素ai的存储地址为:ADR(ai)=ADR(a1)+(i-1)k,ADR(a1)为第一个元素的地址,k代表每个元素占的字节数。 (3)顺序表的运算有查找、插入、删除3种。 1.3 栈 1. 栈的基本概念 栈(stack)是一种特殊的线性表,是限定只在一端进行插入与删除的线性表。 在栈中,一端是封闭的,既不允许进行插入元素,也不允许删除元素;另一端是开口的,允许插入和删除元素。通常称插入、删除的这一端为栈顶,另一端为栈底。当表中没有元素时称为空栈。栈顶元素总是最后被插入的元素,从而也是最先被删除的元素;栈底元素总是最先被插入的元素,从而也是最后才能被删除的元素。 栈是按照“先进后出”或“后进先出”的原则组织数据的。例如,枪械的子弹匣就可以用来形象的表示栈结构。子弹匣的一端是完全封闭的,最后被压入弹匣的子弹总是最先被弹出,而最先被压入的子弹最后才能被弹出。 二级公共基础知识速学教程 2. 栈的顺序存储及其运算 栈的基本运算有3种:入栈、退栈与读栈顶元素。 ① 入栈运算:在栈顶位置插入一个新元素; ② 退栈运算:取出栈顶元素并赋给一个指定的变量; ③ 读栈顶元素:将栈顶元素赋给一个指定的变量。 1.4 队列 1. 队列的基本概念 队列是只允许在一端进行删除,在另一端进行插入的顺序表,通常将允许删除的这一端称为队头,允许插入的这一端称为队尾。当表中没有元素时称为空队列。 队列的修改是依照先进先出的原则进行的,因此队列也称为先进先出的线性表,或者后进后出的线性表。例如:火车进遂道,最先进遂道的是火车头,最后是火车尾,而火车出遂道的时候也是火车头先出,最后出的是火车尾。若有队列: Q =(q1,q2,…,qn) 那么,q1为队头元素(排头

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值