第一题:题目链接: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; }