HOJ1119/HDU1542 Atlantis HOJ1909/POJ1177 Picture

来源:互联网 发布:宝塔linux面板 编辑:程序博客网 时间:2024/06/05 16:42

第一题:题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542

题意:求多个长方形在平面上所覆盖的面积和。

扫描线。从下往上扫描,浮点数离散化处理。

思路参考:http://www.cnblogs.com/scau20110726/archive/2013/03/21/2972808.html

#include <iostream>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;#define Maxn 250#define lx (x<<1)#define rx ((x<<1)|1)#define MID ((l + r)>>1)double X[Maxn];double S[Maxn<<2];int cnt[Maxn<<2];struct Seg{    double l;    double r;    double h;    int s;    Seg(){}    Seg(double _l,double _r,double _h,int _s)    {        l = _l;r = _r;h = _h;s = _s;    }    bool operator <(const Seg & a) const    {        return h<a.h;    }};Seg seg[Maxn];int binarySearch(int l,int r,double x){    while(l<=r)    {        int mid = (l + r)>>1;        if(X[mid] == x) return mid;        if(X[mid]< x) l = mid+1;        else r = mid-1;    }    return 0;}void pushUp(int l,int r,int x){    if(cnt[x]) S[x] = X[r+1] - X[l];    else if(l == r) S[x] = 0;    else S[x] = S[lx] + S[rx];}void update(int L,int R,int d,int l,int r,int x){    if(L<=l && r<=R)    {        cnt[x] += d;        pushUp(l,r,x);        return;    }    if(L<=MID) update(L,R,d,l,MID,lx);    if(MID+1<=R) update(L,R,d,MID+1,r,rx);    pushUp(l,r,x);}void init(){    memset(S,0,sizeof(S));    memset(cnt,0,sizeof(cnt));}int main(){    #ifndef ONLINE_JUDGE    freopen("in.txt","r",stdin);    #endif    int cas = 0;    int n;    double a,b,c,d;    int p = 0;    while(scanf(" %d",&n)!=EOF && n!=0)    {        init();        cas++;        p = 0;        for(int i=0;i<n;i++)        {            scanf(" %lf %lf %lf %lf",&a,&b,&c,&d);            X[p] = a;            seg[p++] = Seg(a,c,b,1);            X[p] = c;            seg[p++] = Seg(a,c,d,-1);        }        sort(X,X+p);        sort(seg,seg+p);        int k = 1;        //去重        for(int i=1;i<p;i++)        {            if(X[i]!=X[i-1]) X[k++] = X[i];        }        //从下往上扫描,忽略最上部边        double ans = 0;        for(int i=0;i<p-1;i++)        {            int l = binarySearch(0,k-1,seg[i].l);            int r = binarySearch(0,k-1,seg[i].r) - 1;            update(l,r,seg[i].s,0,k-1,1);            ans += S[1] * (seg[i+1].h - seg[i].h);        }        printf("Test case #%d\nTotal explored area: %.2lf\n\n",cas,ans);    }    return 0;}


第二题:题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1828

题意:求在平面内的长方形所形成的轮廓的周长。

思路和求面积相似。扫描线从下网上扫描,分为横边长度的记录len[]和竖边个数的记录numSeg[].分别将竖边长度和横边长度的改变绝对值都求出相加即可。

另外要考虑到竖边会重叠。使用lbd[]和rbd[]比对一下是否会重叠。

#include <iostream>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;#define Maxn 15005#define lx (x<<1)#define rx ((x<<1)|1)#define MID ((l + r)>>1)int cnt[Maxn<<2];//在横轴投影的有效长度int len[Maxn<<2];//在横轴投影的有效线段个数×2,即竖边的个数int numSeg[Maxn<<2];//区间左边界是否有竖边bool lbd[Maxn<<2];//区间右边界是否有竖边bool rbd[Maxn<<2];struct Seg{    int l,r,h,s;    Seg(){}    Seg(int _l,int _r,int _h,int _s)    {        l = _l;r = _r;h = _h;s = _s;    }    bool operator <(const Seg &a) const    {        return h<a.h || (h == a.h && s>a.s);    }};Seg seg[Maxn];void pushUp(int l,int r,int x){    if(cnt[x])    {        len[x] = (r - l + 1);        numSeg[x] = 2;        lbd[x] = rbd[x] = 1;    }    else if(l == r)    {        len[x] = numSeg[x] = lbd[x] = rbd[x] = 0;    }    else    {        lbd[x] = lbd[lx];        rbd[x] = rbd[rx];        len[x] = len[lx] + len[rx];        numSeg[x] = numSeg[lx] + numSeg[rx];        if(lbd[rx] && rbd[lx]) numSeg[x] -= 2;    }}void update(int L,int R,int d,int l,int r,int x){    if(L<=l && r<=R)    {        cnt[x]+= d;        pushUp(l,r,x);        return;    }    if(L<=MID) update(L,R,d,l,MID,lx);    if(MID+1<=R) update(L,R,d,MID+1,r,rx);    pushUp(l,r,x);}void init(){    memset(cnt,0,sizeof(cnt));    memset(numSeg,0,sizeof(numSeg));    memset(len,0,sizeof(len));    memset(lbd,0,sizeof(lbd));    memset(rbd,0,sizeof(rbd));}int main(){    #ifndef ONLINE_JUDGE    freopen("in.txt","r",stdin);    #endif    int n;    int a,b,c,d;    int p,last = 0;    while(scanf(" %d",&n)!=EOF)    {        init();        p = 0;        last = 0;        int leftMin = 10005,rightMax = -10005;        for(int i=0;i<n;i++)        {            scanf(" %d %d %d %d",&a,&b,&c,&d);            if(a<leftMin) leftMin = a;            if(c>rightMax) rightMax = c;            seg[p++] = Seg(a,c,b,1);            seg[p++] = Seg(a,c,d,-1);        }        sort(seg,seg+p);        int ans = 0;        for(int i=0;i<p;i++)        {            update(seg[i].l,seg[i].r-1,seg[i].s,leftMin,rightMax-1,1);            //为什么要取绝对值,想一下            //横边长度            ans += abs(len[1] - last);            last = len[1];            //竖边长度            ans += numSeg[1]*(seg[i+1].h-seg[i].h);        }        printf("%d\n",ans);    }    return 0;}







原创粉丝点击