您的位置:首页 > 其它

NYOJ186 Atlantis & POJ 1151

2013-04-26 20:44 260 查看
题目链接: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: