AOJ 1202 Mobile Phone Coverage
問題概要
重なりが許される正方形が与えられる。
実数。
最大100個。
一つ以上の正方形におおわれている部分の面積を求めよ。
解法
y座標でイベント(正方形が始まるのと終わるところ)をソートして、
イベント間にある面積について計算した。
ソース
#include<iostream> #include<algorithm> #include<vector> #include<cmath> #include<cstdio> #define REP(i,b,n) for(int i=b;i<(int)n;i++) #define rep(i,n) REP(i,0,n) #define ALL(C) (C).begin(),(C).end() #define FOR(it,o) for(__typeof((o).begin()) it=(o).begin(); it!=(o).end(); ++it) using namespace std; const int INF = 1000000000; const int N = 100; double l[N], r[N]; bool now[N]; class Id{ public: double y; int id; bool end; bool operator<(const Id &a)const{ return y < a.y; } }; double merge(){ double rightest = -INF, leftest = -INF, ret = 0; vector<pair<double, double> > V; rep(i, N){ if(!now[i])continue; V.push_back(make_pair(l[i], r[i])); } sort(ALL(V)); FOR(it, V){ if(rightest < it->first){ ret += abs(rightest - leftest); leftest = it->first; rightest = it->second; } else { rightest = max(it->second, rightest); } } ret += abs(rightest - leftest); return ret; } int main(){ int n, tc = 0; while(cin >> n){ if(n == 0)break; tc++; vector<Id> V; rep(i, n){ now[i] = false; double x, y, R; cin >> x >> y >> R; V.push_back((Id){y+R, i, true}); V.push_back((Id){y-R, i, false}); l[i] = x - R; r[i] = x + R; } sort(ALL(V)); long double pre = V.front().y, width = 0, ans = 0; FOR(it, V){ if(it->end)now[it->id] = false; else now[it->id] = true; ans += abs(pre - it->y) * width; pre = it->y; width = merge(); } printf("%d %.2Lf\n",tc,ans); } return 0; }