AOJ 1255 Inherit the Spheres
問題
3次元空間に球がいくつかある。
空間を平面z = aで切ったときに、
球と平面の交点は円になるが、その円いくつの連結成分にわかれているか、
z = 0からz = 36000まで、連結成分の個数の変化を出力せよ。
制約条件
n≦100
方針
平面が各球の上下に接する時のz座標、
二球の交わりの部分のうち、最大のz座標と最小のz座標を全て考えればいい。
二球の交わりの部分のz座標の最大値と最小値は、
二球を、一つの球を中心として、z軸についてもう片方の球を回転させてy座標を0にしたときの
xz平面での二円の交わりを見ればいい。
それぞれのz座標のときに、円の連結成分の個数を求めるのは、
適当にunion findしてやればよい。(ワーシャルフロイドだとTLEした)
ソースコード
double d3(double x, double y, double z){ return sqrt(x * x + y * y + z * z); } int n; vector<double> x, y, z, r; vector<double> zs; bool v[100]; int p[100]; double tr[100]; inline int root(int x){ if(x == p[x]) return x; return root(p[x]); } inline void merge(int a, int b){ a = root(a); b = root(b); if(a != b) p[a] = b; } int calc(double h){ rep(i, n){ if(abs(abs(z[i] - h) - r[i]) < EPS) tr[i] = 0; else if(abs(z[i] - h) < r[i] + EPS) tr[i] = sqrt(r[i] * r[i] - (z[i] - h) * (z[i] - h) + EPS); else tr[i] = -1; } int res = 0; rep(i, n) p[i] = i, v[i] = 0; rep(i, n) rep(j, n) if(i != j && tr[i] >= 0 && tr[j] >= 0){ if(abs(P(x[i] - x[j], y[i] - y[j])) < tr[i] + tr[j] + EPS) merge(i, j); } rep(i, n) if(tr[i] >= 0){ int a = root(i); if(!v[a]) v[a] = 1, res++; } return res; } int main(){ while(cin >> n, n){ x.clear(); y.clear(); z.clear(); r.clear(); rep(i, n){ double a, b, c, d; cin >> a >> b >> c >> d; x.pb(a); y.pb(b); z.pb(c); r.pb(d); zs.pb(c - d); zs.pb(c + d); } rep(i, n) rep(j, i) if(i != j) if(d3(x[i] - x[j], y[i] - y[j], z[i] - z[j]) < r[i] + r[j] + EPS){ double dxy = abs(P(x[i] - x[j], y[i] - y[j])); P p1 = P(0, z[i]), p2 = P(dxy, z[j]); pair<P, P> ps = circle_circle_intersect(p1, r[i], p2, r[j]); zs.pb(ps.first.imag()); zs.pb(ps.second.imag()); } zs.pb(0); zs.pb(36000); sort(all(zs)); vector<double> nzs; rep(i, zs.size()){ if(i == 0 || zs[i] > zs[i-1] + EPS) nzs.pb(zs[i]); } string ans; int a; rep(i, nzs.size() - 1){ int b = calc((nzs[i] + nzs[i+1]) / 2); if(i){ if(a == b) ; else if(a < b) ans.pb('1'); else ans.pb('0'); } a = b; } cout << ans.size() << endl; cout << ans << endl; } return 0; }