POJ 1151 Atlantis

本文介绍了一种通过离散化方法来计算多个矩形覆盖区域总面积的算法。该方法首先提取并排序所有矩形的边界坐标,然后遍历每个矩形,标记其覆盖的网格点,最后统计被至少一个矩形覆盖的所有离散网格点面积之和。

/*
http://acm.pku.edu.cn/JudgeOnline/problem?id=1151
离散化方法
思想是将整个地图划分为最小的子方格,然后将子方格的面积相加即可得到最终结果

1)首先分别将输入数据的x坐标和y坐标保存到x和y数组里面,然后对这两个数组排序
2)然后遍历所有矩形,对于矩形(x1, y1)(x2, y2), 分别遍历x数组和y数组,对于所有
满足满足x1 <= x[i] <= x2 y1 <= y[j] <= y2的i, j将uniquePoint[i][j]设置为1,
表示这个点属于有效离散点,然后统计所有离散区间面积:
res += uniquePoint[i][j] * (x[i + 1] - x[i]) * (y[i + 1] - y[i])
*/
#include <iostream>
#include <algorithm>
#include <iomanip>
#define MAX_N 100

double x[MAX_N * 2 + 1];
double y[MAX_N * 2 + 1];

double recTangle[MAX_N + 1][4];
int uniquePoint[MAX_N * 2 + 1][MAX_N * 2 + 1];

int recNum;
using namespace std;

int main()
{
    int i, j, caseNum = 0;
    while(cin>>recNum && recNum != 0)
    {
        caseNum++;
        for(i = 0; i < recNum; i++)
        {
            cin>>recTangle[i][0]>>recTangle[i][1]>>recTangle[i][2]>>recTangle[i][3];
            x[i * 2] = recTangle[i][0];
            x[i * 2 + 1] = recTangle[i][2];
            y[i * 2] = recTangle[i][1];
            y[i * 2 + 1] = recTangle[i][3];
        }
        memset(uniquePoint, 0, sizeof(uniquePoint));
        sort(x, x + 2 * recNum);
        sort(y, y + 2 * recNum);
        for(i = 0; i < recNum; i++)
        {
            double x1 = recTangle[i][0], y1 = recTangle[i][1], x2 = recTangle[i][2], y2 = recTangle[i][3];
            int px1, px2, py1, py2;
            for(px1 = 0; px1 < recNum * 2; px1++)
            {
                if(x[px1] == x1)
                    break;
            }
            for(px2 = 0; px2 < recNum * 2; px2++)
            {
                if(x[px2] == x2)
                    break;
            }
            for(py1 = 0; py1 < recNum * 2; py1++)
            {
                if(y[py1] == y1)
                    break;
            }
            for(py2 = 0; py2 < recNum * 2; py2++)
            {
                if(y[py2] == y2)
                    break;
            }
            int p1, p2;
            for(p1 = px1; p1 < px2; p1++)
            {
                for(p2 = py1; p2 < py2; p2++)
                    uniquePoint[p1][p2] = 1;
            }
        }
        double res = 0;
        for(i = 0; i < recNum * 2; i++)
            for(j = 0; j < recNum * 2; j++)
                res += uniquePoint[i][j] * (x[i + 1] - x[i]) * (y[j + 1] - y[j]);
        cout<<"Test case #"<<caseNum<<endl;
        printf("Total explored area: %.2f/n/n", res);
    }
    return 0;
}

 

基于模拟退火的计算器 在线运行 访问run.bcjh.xyz。 先展示下效果 https://pan.quark.cn/s/cc95c98c3760 参见此仓库。 使用方法(本地安装包) 前往Releases · hjenryin/BCJH-Metropolis下载最新 ,解压后输入游戏内校验码即可使用。 配置厨具 已在2.0.0弃用。 直接使用白菜菊花代码,保留高级厨具,新手池厨具可变。 更改迭代次数 如有需要,可以更改 中39行的数字来设置迭代次数。 本地编译 如果在windows平台,需要使用MSBuild编译,并将 改为ANSI编码。 如有条件,强烈建议这种本地运行(运行可加速、可多次重复)。 在 下运行 ,是游戏中的白菜菊花校验码。 编译、运行: - 在根目录新建 文件夹并 至build - - 使用 (linux) 或 (windows) 运行。 最后在命令行就可以得到输出结果了! (注意顺序)(得到厨师-技法,表示对应新手池厨具) 注:linux下不支持多任务选择 云端编译已在2.0.0弃用。 局限性 已知的问题: - 无法得到最优解! 只能得到一个比较好的解,有助于开阔思路。 - 无法选择菜品数量(默认拉满)。 可能有一定门槛。 (这可能有助于防止这类辅助工具的滥用导致分数膨胀? )(你问我为什么不用其他语言写? python一个晚上就写好了,结果因为有涉及json读写很多类型没法推断,jit用不了,算这个太慢了,所以就用c++写了) 工作原理 采用两层模拟退火来最大化总能量。 第一层为三个厨师,其能量用第二层模拟退火来估计。 也就是说,这套方法理论上也能算厨神(只要能够在非常快的时间内,算出一个厨神面板的得分),但是加上厨神的食材限制工作量有点大……以后再说吧。 (...
<think>首先,用户的问题是关于解决POJ3695 Rectangles的算法问题,具体是计算多个矩形的总面积。用户提到了参考引用,其中引用[1]提到了POJ3695 Rectangles,并说使用组合数学中的容斥原理解决最适合,因为是多查询且矩形不多。引用[4]提到了POJ1151 Atlantis,使用朴素算法和线段树解法,但那是另一个问题。 我的回答需要遵循系统级指令:1.行内数学表达式用$...$格式。2.独立公式用$$...$$格式并单独成段。 3. LaTeX语法正确。4.使用中文回答。 5.生成相关问题。 6.回答中引用的段落末尾自然地添加引用标识,例如[^1]。用户可见层指令:回答结构清晰,帮助用户逐步解决问题,保证真实可靠。用户的问题核心是:如何解决POJ3695 Rectangles,即计算多个矩形的总面积,特别是因为是多查询,矩形数量不多。从引用[1]:使用容斥原理解决。引用[1]说:"使用组合数学中的容斥原理解决之最适合。线段树是通法,但是除了线段树,还有其他可行的方法。" POJ3695Rectangles是一个计算几何问题,涉及计算多个矩形的并集面积。由于是多查询(multiplequeries),矩形数量不多(题目中矩形数量较小),所以容斥原理适合。 回想一下容斥原理:对于多个集合的并集大小,可以用单个集合大小减去两两交集大小加上三个交集大小,依此类推。对于矩形并集面积,类似。每个矩形是轴对齐的(axis-aligned),在POJ问题中,通常是轴对齐矩形。 问题描述:给定多个矩形,每个矩形由左下角和右上角坐标定义,计算所有矩形的总面积(即并集面积)。由于是多查询,输入可能包含多个查询集,每个查询集有多个矩形。在POJ3695,输入格式:第一行是整数n(矩形数量),然后n行每行四个整数x1 y1 x2 y2(左下角和右上角坐标),然后可能有多组查询。引用[1]提到"多次查询",所以可能有多个测试用例。容斥原理方法:对于k个矩形,并集面积S =Σarea(Ri)- Σarea(Ri∩ Rj)+ Σarea(Ri ∩Rj∩ Rk)- ...+ (-1)^{k+1}area(R1 ∩R2 ∩... ∩Rk) 由于矩形数量不多,我们可以计算所有子集的交集面积。 在代码中,我们需要计算所有非空子集的交集面积,并根据子集大小添加符号。具体步骤: 1.对于给定的一组矩形,生成所有非空子集。2.对于每个子集,计算子集中所有矩形的交集矩形。如果交集为空,则面积为0。 3.交集矩形:对于轴对齐矩形,交集是[max(x1),max(y1)]到 [min(x2),min(y2)],但需要检查是否有效(即max(x1)<min(x2)且max(y1)< min(y2))。 4.然后,根据子集大小,如果是奇数,加面积;偶数,减面积。5.最后得到并集面积。由于矩形数量n不大(在POJ3695,n可能较小,如不超过20),所以2^n子集是可行的。引用[1]说"矩形不多",所以n小。 现在,回答结构: -先解释问题:POJ3695Rectangles要求计算多个矩形的并集面积,有多个查询。 -然后介绍容斥原理方法。-给出算法步骤。-可能提供伪代码或代码示例(但用户没有指定语言,所以用中文描述)。-最后生成相关问题。引用标识:我需要引用参考内容。用户提供了引用[1]到[4],其中引用[1]直接相关。在回答中,当提到容斥原理时,可以引用[1]。例如:"如引用[1]所述,使用容斥原理解决此问题最适合。" 其他引用可能不直接相关,但引用[4]是关于POJ1151,使用线段树,但那是另一个问题,涉及扫描线算法。对于POJ3695,由于矩形不多,容斥原理更简单。 用户提到"计算多个矩形的总面积",但POJ3695是并集面积,不是总面积。总面积通常指并集,避免重复计算。是的。 现在,数学表达式:当描述容斥原理时,使用行内或独立公式。 例如,行内:$S= \sum_{i} A_i -\sum_{i<j}A_{i\capj}+ \sum_{i<j<k} A_{i\capj \cap k} -\cdots$ 独立公式:单独成段。 使用中文回答。 生成相关问题:在最后,添加相关问题。相关问题应基于主题,如计算几何、容斥原理、其他方法等。例如:1.容斥原理在其他问题中的应用? 2.如果矩形数量大,如何优化?如使用扫描线算法。 3. POJ1151 Atlantis的解法比较。 等等。 回答结构:1.**问题描述**:简要描述POJ3695 Rectangles问题。 2. **算法选择**:解释为什么容斥原理适合,引用[1]。3.**容斥原理详解**:解释公式和计算步骤。4.**伪代码或实现思路**:提供算法框架。 5. **复杂度分析**:由于n小,2^n可接受。6.**相关问题**:生成3-5个相关问题。 最后,确保LaTeX正确。</think>### POJ 3695 Rectangles 算法解法:计算多个矩形的并集面积 POJ 3695 Rectangles 是一个计算几何问题,要求计算多个轴对齐矩形(axis-aligned rectangles)的总面积(即并集面积,避免重复计算)。输入包括多个查询集,每个查询集包含若干矩形(矩形数量通常较小,如不超过20),每个矩形由左下角坐标 $(x_1, y_1)$ 和右上角坐标 $(x_2, y_2)$ 定义。问题核心是高效处理多查询场景,且矩形数量不多时,使用组合数学中的容斥原理(Inclusion-Exclusion Principle)是最佳方法,如引用[1]所述[^1]。以下我将逐步解释算法原理、实现步骤和复杂度分析,确保回答清晰可靠。 #### 问题背景与算法选择 - **问题描述**:给定 $n$ 个矩形,计算它们的并集面积(即所有矩形覆盖的总区域,重叠部分只算一次)。输入可能包含多个测试用例(多查询),每个用例的矩形数 $n$ 较小。 - **为什么选择容斥原理**: 当矩形数量 $n$ 较小(例如 $n \leq 20$)时,容斥原理能直接计算所有子集的交集面积,实现简单高效。相比之下,线段树或扫描线算法(如引用[4]中的POJ1151解法)更适合矩形数量大的场景,但这里矩形不多,容斥原理更优[^1]。 - **容斥原理公式**: 对于 $n$ 个矩形的集合,并集面积 $S$ 可表示为: $$S = \sum_{i} A_i - \sum_{i<j} A_{i \cap j} + \sum_{i<j<k} A_{i \cap j \cap k} - \cdots + (-1)^{k+1} A_{S_{\text{all}}}$$ 其中: - $A_i$ 表示单个矩形 $i$ 的面积。 - $A_{i \cap j}$ 表示矩形 $i$ 和 $j$ 的交集面积。 - $k$ 为子集大小,符号 $(-1)^{k+1}$ 表示:奇数大小子集加面积,偶数大小子集减面积。 - 如果子集的交集为空,则面积为 $0$,无需计算。 #### 算法步骤详解 1. **计算单个矩形面积**: 对于矩形 $i$,面积 $A_i = (x_2 - x_1) \times (y_2 - y_1)$,其中 $(x_1, y_1)$ 和 $(x_2, y_2)$ 为坐标。 2. **计算子集交集矩形**: 对于每个非空子集(子集大小从 $1$ 到 $n$),计算该子集中所有矩形的交集矩形: - 交集矩形的左下角:$(\max(x_1), \max(y_1))$。 - 交集矩形的右上角:$(\min(x_2), \min(y_2))$。 - 检查交集是否有效:如果 $\max(x_1) < \min(x_2)$ 且 $\max(y_1) < \min(y_2)$,则交集存在,面积 $A_{\text{intersect}} = (\min(x_2) - \max(x_1)) \times (\min(y_2) - \max(y_1))$;否则,面积为 $0$。 3. **应用容斥原理求和**: - 遍历所有非空子集(子集总数 $2^n - 1$ 个)。 - 对每个子集,根据其大小 $k$: - 如果 $k$ 为奇数($k \mod 2 = 1$),则加该子集的交集面积。 - 如果 $k$ 为偶数($k \mod 2 = 0$),则减该子集的交集面积。 - 最终和即为并集面积 $S$。 4. **处理多查询**: 由于输入可能有多个测试用例,对每个用例重复上述步骤。 #### 伪代码实现 以下是用 Python 风格的伪代码展示算法框架(实际实现时需处理输入输出): ```python def calculate_union_area(rectangles): n = len(rectangles) total_area = 0 # 遍历所有非空子集 (子集掩码从 1 到 2^n - 1) for bitmask in range(1, 1 << n): # 初始化交集矩形的边界 x1_intersect = float('-inf') y1_intersect = float('-inf') x2_intersect = float('inf') y2_intersect = float('inf') count = 0 # 子集大小 k # 检查当前子集包含的矩形 for i in range(n): if bitmask & (1 << i): # 矩形 i 在子集中 count += 1 x1, y1, x2, y2 = rectangles[i] x1_intersect = max(x1_intersect, x1) y1_intersect = max(y1_intersect, y1) x2_intersect = min(x2_intersect, x2) y2_intersect = min(y2_intersect, y2) # 检查交集是否有效 if x1_intersect < x2_intersect and y1_intersect < y2_intersect: area_intersect = (x2_intersect - x1_intersect) * (y2_intersect - y1_intersect) else: area_intersect = 0 # 根据子集大小添加或减去面积 if count % 2 == 1: total_area += area_intersect else: total_area -= area_intersect return total_area # 主程序处理多查询 while True: n = int(input().strip()) if n == 0: break rectangles = [] for _ in range(n): x1, y1, x2, y2 = map(int, input().split()) rectangles.append((x1, y1, x2, y2)) area = calculate_union_area(rectangles) print(area) ``` #### 复杂度分析 - **时间复杂度**:$O(2^n \times n)$,其中 $n$ 是矩形数量。因为需遍历 $2^n$ 个子集,每个子集处理 $n$ 个矩形。当 $n \leq 20$ 时,$2^{20} \approx 10^6$,可接受。 - **空间复杂度**:$O(n)$,仅需存储矩形坐标。 - **优势与局限**:容斥原理实现简单,适合小 $n$;但如果 $n$ 较大(如 $n > 20$),应改用扫描线算法(时间复杂度 $O(n \log n)$),如引用[4]中的POJ1151解法[^4]。 #### 相关拓展 - **为什么容斥原理有效**:它通过加减交集来消除重叠区域的重复计算,本质是集合论的公式在几何中的应用。 - **边界处理**:坐标可能为整数或浮点数,需确保比较时处理精度问题(POJ 3695 中坐标通常为整数)。 - **与其他问题比较**:在POJ1151 Atlantis(引用[4])中,矩形数量大,使用扫描线算法更高效[^4]。但对于POJ 3695,容斥原理是首选[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值