NYOJ186 Atlantis & POJ 1151

43 篇文章 0 订阅
3 篇文章 0 订阅

题目链接:POJ题目 VS NYOJ题目
题目分析:
这道题其实是求一系列矩形并的面积。典型的有两种方法,一种是用区间树来做,另一种是矩形切割的方法。不过这道题的数据量很大。用矩形切割的话,内存会溢出。不过暂时没有搞通区间树的方法,所以还是贴上法的的代码,但是对于POJ1151是可以的,因为那里的矩形数最多也就100个,而NYOJ上面矩形数最多有10000个。稍后再给出区间数的解法。
矩形分割的解决步骤
1、用一个list来存放所有不相交的矩形,因为list的插入删除比较方便。
2、输入矩形r2的坐标,判断与list里面所有矩形是否相交。假设与矩形r1相交,用r2将r1分成小矩形,然后将与r2不相交的部分小矩形压到list中,最后再将r2压入list中。
3、遍历整个list里面的矩形,求面积和。
怎么判断两个矩形相交?
由于这里的矩形都是平行于坐标轴的,所以两个矩形的中心的距离(x,y)分别小于两个矩形的宽、长的和的一半,则两个矩形相交。
怎么把两个矩形分成小矩形?
这里是通过r2来分割r1,并且将r1与r2不相交的部分压入list中。自己画画图分析分析。首先找出相交的两个点,也就是代码中说的。然后相交的部分保留在r2中,然后以相交的点将r1切割。题目分析:
另外一种方法是用区间树来做,还没有搞透,搞透之后再来分析~

#include<stdio.h>
#include<math.h>
#include<list>
struct RECT
{
	double x1,y1;
	double x2,y2;
	RECT():x1(0),y1(0),x2(0),y2(0) {}
	RECT(double x1, double y1, double x2, double y2):x1(x1),y1(y1),x2(x2),y2(y2){}
};
std::list<RECT> link;
inline double max(const double a, const double b)
{
	return a > b ? a : b;
}
inline double min(const double a, const double b)
{
	return a < b ? a : b;
}
//判断矩形是否相交
bool IsCross(const RECT &r1, const RECT &r2)
{
	double l1 = fabs(r1.x1 + r1.x2 - r2.x1 - r2.x2) - (r1.x2 - r1.x1) - (r2.x2 - r2.x1);
	double l2 = fabs(r1.y1 + r1.y2 - r2.y1 - r2.y2) - (r1.y2 - r1.y1) - (r2.y2 - r2.y1);
	if(l1 < 0 && l2 < 0)
		return true;
	else
		return false;
}
//用矩形r2来切割r1
void CutIntoPiece(const RECT &r1, const RECT &r2)
{
	double lx = max(r1.x1, r2.x1);//相交部分的左下x坐标
	double rx = min(r1.x2, r2.x2);//相交部分的右上x坐标
	double ly = max(r1.y1, r2.y1);//相交部分的左下y坐标
	double uy = min(r1.y2, r2.y2);//相交部分的右上y坐标
	if(r1.x1 < lx)
		link.push_back(RECT(r1.x1, r1.y1, lx, r1.y2));
	if(rx < r1.x2)
		link.push_back(RECT(rx, r1.y1, r1.x2, r1.y2));
	if(r1.y1 < ly)
		link.push_back(RECT(lx, r1.y1, rx, ly));
	if(uy < r1.y2)
		link.push_back(RECT(lx, uy, rx, r1.y2));
}
int main()
{
	int n,i,t;
	RECT rect;
	std::list<RECT>::iterator it,EndIt,TempIt;
	double sum;
	t = 0;
	while(scanf("%d", & n))
	{
		if(!n)
			break;
		link.clear();
		for(i = 0; i < n; ++i)
		{
			scanf("%lf %lf %lf %lf", &rect.x1, &rect.y1, &rect.x2, &rect.y2);
			EndIt = link.end();//只遍历到原来的链表尾,新加入的RECT不用遍历了
			for(it = link.begin(); it != EndIt; )
			{
				if(IsCross(*it, rect))/如果相交,则划分矩形
				{
					CutIntoPiece(*it, rect);
					TempIt = it;
					++it;
					link.erase(TempIt);
				}
				else
					++it;
			}
			link.push_back(rect);
		}//end Input
		sum = 0.0;
		for(it = link.begin(); it != link.end(); ++it)
			sum += (it->x2 - it->x1) * (it->y2 - it->y1);
		printf("Test case #%d\nTotal explored area: %.2lf\n\n", ++t, sum);
	}//end while
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值