c语言给定n个矩形,矩形的并

这篇博客介绍了如何在X-Y坐标平面上,针对多个与坐标轴平行的矩形,计算它们并集的面积。首先,通过投影矩形的边界到X轴上生成水平线段,然后采用排序和扫描线算法统计重叠部分的面积。博客提供了C++代码实现,通过投影、排序和区间统计来解决这一问题,避免了复杂的递归或分治策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述

在 X-Y 坐标平面上,给定多个矩形,它们的边分别与坐标轴平行。请计算它们的并的面积。

输入格式

输入第一行为一个整数 n,1<=n<=100,表示矩形的数量。

接下来有 n 行,每行包括四个数:x1,y1,x2,y2 (0<=x1

(x1,y1)表示一个长方形的左下顶点坐标,(x2,y2)表示右上顶点坐标。

输出格式

n个矩形的并的面积,保留两位小数。

输入样例

2

0 0 2 2

1 1 3 3

输出样例

7.00

Hint

此题没能用上递归、分治或其他等一系列方法。以下为推荐思路,鼓励自行思考别的方法。

第一题本为练笔,但我挑选的此题似乎实现起来麻烦。

对不住大家了!若实在觉得繁琐的可跳过此题。:(

但,练练手总没坏处滴 :)

多个矩形面积重叠没有规律,难以直接求解或用上递归的思路。

只能从矩形重叠的情况入手,进行局部相加。

1)将所有矩形的左右边界都投影到X轴上,形成各个区间

2)从左向右计算每个区间,将落在该区间内的矩形进行面积统计

3)将每个区间计算的面积再相加

1.[代码][C/C++]代码

#include

#include

using namespace std;

typedef struct LevelSeg //用来记录一个水平线段的结构体

{

double l, r; //l是水平线段的的左顶点x坐标,r是水平线段的右顶点x坐标

double y; //y是一个水平线段的y坐标

int UpOrDown; //标记这个水平线段是上边还是下边, 0 是下边,1 是上边

}LevelSeg;

// 对LevelSeg按照Y坐标的值进行从大到小的排序

int Partition(LevelSeg L[], int low, int high) {

L[0] = L[low];

double pivotkey = L[low].y;

while(low < high) {

while(low < high && L[high].y <= pivotkey) --high;

L[low] = L[high];

while(low < high && L[low].y >= pivotkey) ++low;

L[high] = L[low];

}

L[low] = L[0];

return low;

}

void qsort(LevelSeg L[], int low, int high) {

if(low < high) {

double pivotloc = Partition(L, low, high);

qsort(L, low, pivotloc - 1);

qsort(L, pivotloc + 1, high);

}

}

int main() {

int n = 0;

double x1, x2, y1, y2;

LevelSeg ls[201];

set X; // 记录所有x坐标

double area = 0;

scanf("%d", &n);

// 初始化所有矩形

if(n >= 1 && n <=100) {

for(int i = 1; i <= 2*n; i += 2) {

scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);

ls[i].l = x1;

ls[i].r = x2;

ls[i].y = y1;

ls[i].UpOrDown = 0; // 下边

ls[i+1].l = x1;

ls[i+1].r = x2;

ls[i+1].y = y2;

ls[i+1].UpOrDown = 1; // 上边

X.insert (x1);

X.insert (x2);

}

}

// 对LevelSeg进行排序

qsort(ls,1,2*n);

set::iterator di;

di = X.begin();

for(int j = 1; j< X.size(); j ++){

int mark = 0;

double maxY = 0;

int count = 0; // 计数器

x1 = *(di);

x2 = *(++di);

//std::cout << *di << " ";

for(int i = 1; i <= 2*n; i ++){

if(x1 >= ls[i].l && x2 <= ls[i].r){

if(0 == mark) {

maxY = ls[i].y;

mark = 1;

}

if(ls[i].UpOrDown) {

count ++;

}else {

count --;

}

if(0 == count){

area += (x2 - x1)*(maxY - ls[i].y);

mark = 0;

}

}

}

}

printf("%.2lf", area);

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值