POJ 1151 Atlantis(重叠矩阵面积和=离散化)
http://poj.org/problem?id=1151
题意: ZOJ 1128
给你n个边平行于坐标轴的矩阵(任意两个矩阵可能重叠),让要你求这些矩阵的总面积.(注意x1<x2且y1<y2)
分析:
本题可以用线段树扫描线做,不过终归还是用离散化的思想来做,下面直接离散化做.(未使用线段树)
假设输入的矩阵中共有num1个不同的x坐标和num2个不同的y坐标,那么整个二维平面就被分割成了(num1-1)*(num2-1)个小方格矩形.
我们只要看上面(num1-1)*(num2-1)个小方格矩形哪些被某个大矩形覆盖,哪些没有被任何一个大矩形覆盖即可.
我们令mp[i][j]=1表示以(x[i], y[j])点为左上角,以(x[i+1], y[j+1])点为右上角的那个小矩形被某个大矩形覆盖了.
假设大矩形I的x坐标范围在[xi,xj]之间而y坐标在[yk,yh]之间.那么该大矩阵I肯定使得 所有的mp[a][b]==1. 其中i<=a<k且j<=b<h.
如上图两个绿色的矩阵正好使得了7个小矩阵被覆盖.那些小矩形对应的mp值都是1.
最终我们只要把那些mp值==1的小矩形面积加起来即可.
AC代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=200+5;
struct Node//矩形
{
double x1,y1,x2,y2;
}nodes[maxn];
double x[maxn],y[maxn];
bool mp[maxn][maxn];
int find(double *x,double val,int n)//在数组x中找到val值的位置
{
int L=0,R=n-1;
while(R>=L)
{
int mid=L+(R-L)/2;
if(x[mid]==val) return mid;
else if(x[mid]>val) R=mid-1;
else L=mid+1;
}
return -1;
}
int main()
{
int n,num1,num2,kase=0;
while(scanf("%d",&n)==1 && n)
{
num1=num2=0;//num1记录有多少个不同x值,num2记录y的
memset(mp,0,sizeof(mp));
for(int i=0;i<n;++i)
{
scanf("%lf%lf%lf%lf",&nodes[i].x1,&nodes[i].y1,&nodes[i].x2,&nodes[i].y2);
x[num1++]=nodes[i].x1;
x[num1++]=nodes[i].x2;
y[num2++]=nodes[i].y1;
y[num2++]=nodes[i].y2;
}
sort(x,x+num1);
sort(y,y+num2);
num1=unique(x,x+num1)-x;//去重
num2=unique(y,y+num2)-y;//去重
for(int i=0;i<n;++i)
{
//找出第i个原始大矩形覆盖的小矩形范围
int L_x=find(x,nodes[i].x1,num1);
int R_x=find(x,nodes[i].x2,num1);
int L_y=find(y,nodes[i].y1,num2);
int R_y=find(y,nodes[i].y2,num2);
for(int j=L_x;j<R_x;++j)
for(int k=L_y;k<R_y;++k)
mp[j][k]=true;
}
double ans=0;
for(int i=0;i<num1;++i)
for(int j=0;j<num2;++j)if(mp[i][j])
ans += (x[i+1]-x[i])*(y[j+1]-y[j]);
printf("Test case #%d\nTotal explored area: %.2lf\n\n",++kase,ans);
}
return 0;
}