【转】poj_1151(Atlantis)

Atlantis
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 8189   Accepted: 3228

Description

There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.

Input

The input consists of several test cases. Each test case starts with a line containing a single integer n (1 <= n <= 100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0 <= x1 < x2 <= 100000;0 <= y1 < y2 <= 100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.
The input file is terminated by a line containing a single 0. Don't process it.

Output

For each test case, your program should output one section. The first line of each section must be "Test case #k", where k is the number of the test case (starting with 1). The second one must be "Total explored area: a", where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.
Output a blank line after each test case.

Sample Input

2
10 10 20 20
15 15 25 25.5
0

Sample Output

Test case #1
Total explored area: 180.00 

Source

方法一:
离散化+线段树
 
AC代码:
 
#include <iostream>
#include <algorithm>
using namespace std;
#define lch(a) (2*(a))
#define rch(a) (2*(a)+1)
#define MAXN 105
struct Line
{
    double x,y1,y2;//竖直线段的上下端点y1,y2和位置x
    int side;//side=1表示左线段,side=-1表示右线段
};
struct Line L[2*MAXN];
struct Tree
{
    double y1,y2,x;
    int cover;//用以表示加进线段树中的线段次数
    bool flag;//此标记用来表示是否有超元线段;为了处理方便加上去的
};
struct Tree Tnode[8*MAXN];
double Y[2*MAXN];
int K;//有K组不同的y值(离散化)
bool cmp(Line a,Line b)//比较函数,用于排序(按X从小到大)
{
    return a.x<b.x;
}
void Build(int p,int s,int e)
{
    Tnode[p].x=-1;//-1表示该区间没有线段
    Tnode[p].cover=0;
    Tnode[p].y1=Y[s];//注意
    Tnode[p].y2=Y[e];
    Tnode[p].flag=false;//表示还可以往下分
    if(s+1==e)
    {
        Tnode[p].flag=true;//表示分到底了
        return;
    }
    int mid=(s+e)>>1;
    Build(lch(p),s,mid);
    Build(rch(p),mid,e);
}
double Insert(int p,double x,double s,double e,int side)
{
    if(e<=Tnode[p].y1||s>=Tnode[p].y2)
        return 0;
    if(Tnode[p].y1>=s&&Tnode[p].y2<=e&&Tnode[p].flag)//注意一定要分到底
    {
        if(Tnode[p].cover>0)//说明有左线段
        {
            double temp_x=Tnode[p].x;//注意
            Tnode[p].x=x;//x往右移
            Tnode[p].cover+=side;//更新边的情况
            return (Tnode[p].y2-Tnode[p].y1)*(x-temp_x);
        }
        else//不能构成矩形
        {
            Tnode[p].x=x;
            Tnode[p].cover+=side;
            return 0;
        }
    }
    double ans1=Insert(lch(p),x,s,e,side);
    double ans2=Insert(rch(p),x,s,e,side);
    return ans1+ans2;
}
int main()
{
    int t,cas=1,i;
    double x1,x2,y1,y2;
    while(scanf("%d",&t)!=EOF)
    {
        if(t==0) break;
        printf("Test case #%d/n",cas++);
        K=1;
        for(i=1;i<=t;i++)//数据输入
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            L[K].x=x1;
            L[K].y1=y1;//小
            L[K].y2=y2;//大
            L[K].side=1;
            Y[K]=y1;
            K++;
            L[K].x=x2;
            L[K].y1=y1;//小
            L[K].y2=y2;//大
            L[K].side=-1;
            Y[K]=y2;
            K++;
        }   
        sort(L+1,L+K,cmp);//按x对边排序
        sort(Y+1,Y+K);//对Y排序
        Build(1,1,K-1);//建树(范围为K)
        double ans=0;//存答案
        for(i=1;i<K;i++)
            ans+=Insert(1,L[i].x,L[i].y1,L[i].y2,L[i].side);
        printf("Total explored area: %.2lf/n/n",ans);   
    }
return 0;
}
---------------------------------------------------------------------------------------------------------------------------------------------------
方法二:(网上看来得)
离散化XY:
 
这道题是离散化的入门题。
问题描述:一些已知右下顶点和左上顶点坐标的矩形,这些矩形可能部分重叠,求它们所占的实际面积。
方案一、
把矩形映射到数组M[ ][ ]中,如果某矩形的位置为(x1,y1)(x2,y2)则M[i][j]=1(其中x1<=i<=x2,y1<=j<=y2)。但是,如果坐标值离散程度很大或者非整型,此方案就不可行。
方案二、
判断任两个矩形是否相交,如果重叠,两面积相加,减去重叠部分。但重叠情况很多,算法不复杂但程序写起来很复杂,容易出错。
方案三——离散化
1、首先分离出所有的横坐标和纵坐标分别按升序存入数组X[ ]和Y[ ]中.
2、 设数组XY[ ][ ].对于每个矩形(x1,y1)(x2,y2)确定i1,i2,j1,j2,使得,X[i1]>x1,X[i2]<=x2,Y[i1]>y1,Y[i2]>=y2令XY[ i ][ j ] = 1 (i从i1到i2,j从j1到j2)
3、统计面积:area+=XY[i][j] *(X[i]-X[i-1])*(Y[i] – Y[i-1])
 
AC代码:
#include<iostream>
#include <algorithm>
using namespace std;
double x[201],y[201],s[101][4];
int xy[201][201];
int n,cas=0;
double sum;
int main()
{
    int i,j,k;
    while(cin>>n)
    {  
        if(n==0)
            break;
        cas++;
        k=0;
        sum=0.0;
        memset(xy,0,sizeof(xy));
        for(i=1;i<=n;i++)
        {
            cin>>s[i][0]>>s[i][1]>>s[i][2]>>s[i][3];
            x[k]=s[i][0];
            y[k]=s[i][1];
            k++;
            x[k]=s[i][2];
            y[k]=s[i][3];
            k++;
        }
        sort(x,x+2*n);
        sort(y,y+2*n);
        for(k=1;k<=n;k++)
        {
            int i1,i2,j1,j2;
            for(i1=0;i1<2*n;i1++)
            {
                if(x[i1]==s[k][0])
                    break;
            }
            for(i2=0;i2<2*n;i2++)
            {
                if(x[i2]==s[k][2])
                    break;
            }
            for(j1=0;j1<2*n;j1++)
            {
                if(y[j1]==s[k][1])
                    break;
            }
            for(j2=0;j2<2*n;j2++)
            {
                if(y[j2]==s[k][3])
                    break;
            }
            for(i=i1;i<i2;i++)
            {
                for(j=j1;j<j2;j++)
                {
                    xy[i][j]=1;
                }
            }
        }
        for(i=0;i<2*n;i++)
        {
            for(j=0;j<2*n;j++)
            {
                sum+=xy[i][j]*(x[i+1]-x[i])*(y[j+1]-y[j]);
            }
        }
        printf("Test case #%d/n",cas);
        printf("Total explored area: %.2f/n",sum);
        printf("/n");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lzhitian/p/2590065.html