Problem:
Problem H: Inherit the Spheres

In the year 2xxx, an expedition team landing on a planet found strange objects made by an
ancient species living on that planet. They are transparent boxes containing opaque solid spheres
(Figure 1). There are also many lithographs which seem to contain positions and radiuses of
spheres.

Figure 1: A strange object

Initially their objective was unknown, but Professor Zambendorf found the cross section formed
by a horizontal plane plays an important role. For example, the cross section of an object
changes as in Figure 2 by sliding the plane from bottom to top.

Figure 2: Cross sections at different positions

He eventually found that some information is expressed by the transition of the number of
connected figures in the cross section, where each connected figure is a union of discs intersecting
or touching each other, and each disc is a cross section of the corresponding solid sphere. For
instance, in Figure 2, whose geometry is described in the first sample dataset later, the number
of connected figures changes as 0, 1, 2, 1, 2, 3, 2, 1, and 0, at z = 0.0000, 162.0000, 167.0000,
173.0004, 185.0000, 191.9996, 198.0000, 203.0000, and 205.0000, respectively. By assigning 1 for
increment and 0 for decrement, the transitions of this sequence can be expressed by an 8-bit
binary number 11011000.

For helping further analysis, write a program to determine the transitions when sliding the
horizontal plane from bottom (z = 0) to top (z = 36000).

Input

The input consists of a series of datasets. Each dataset begins with a line containing a positive
integer, which indicates the number of spheres N in the dataset. It is followed by N lines
describing the centers and radiuses of the spheres. Each of the N lines has four positive integers
Xi, Yi, Zi, and Ri (i = 1, . . . , N) describing the center and the radius of the i-th sphere,
respectively.

You may assume 1 ≤ N ≤ 100, 1 ≤ Ri ≤ 2000, 0 < Xi - Ri < Xi + Ri < 4000, 0 < Yi - Ri < Yi + Ri < 16000, and 0 < Zi - Ri < Zi + Ri < 36000. Each solid sphere is defined as the set of
all points (x, y, z) satisfying (x - Xi)2 + (y - Yi)2 + (z - Zi)2 ≤ Ri2.

A sphere may contain other spheres. No two spheres are mutually tangent. Every Zi ± Ri and
minimum/maximum z coordinates of a circle formed by the intersection of any two spheres differ
from each other by at least 0.01.

The end of the input is indicated by a line with one zero.

Output

For each dataset, your program should output two lines. The first line should contain an integer
M indicating the number of transitions. The second line should contain an M-bit binary number
that expresses the transitions of the number of connected figures as specified above.

Sample Input

3
95 20 180 18
125 20 185 18
40 27 195 10
1
5 5 5 4
2
5 5 5 4
5 5 5 3
2
5 5 5 4
5 7 5 3
16
2338 3465 29034 710
1571 14389 25019 842
1706 8015 11324 1155
1899 4359 33815 888
2160 10364 20511 1264
2048 8835 23706 1906
2598 13041 23679 618
1613 11112 8003 1125
1777 4754 25986 929
2707 9945 11458 617
1153 10358 4305 755
2462 8450 21838 934
1822 11539 10025 1639
1473 11939 12924 638
1388 8519 18653 834
2239 7384 32729 862
0

Output for the Sample Input

8
11011000
2
10
2
10
2
10
28
1011100100110101101000101100

Solution in C++ (judge verdict: Accepted)

#include<iostream>
#include<complex>
#include<algorithm>
#include<vector>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define ALL(C)     (C).begin(),(C).end()
#define pb         push_back
#define mp         make_pair

const double eps = 1e-10;

typedef complex<double> P;

class Point{
public:
  double x,y,z;
};

class DisjointSet{
public:
  vector<int> rank,p;
  DisjointSet(){}
  DisjointSet(int size){
    rank.resize(size,0);
    p.resize(size,0);
  }
  
  void makeset(int x){
    p[x]=x;
    rank[x]=0;
  }
  void merge(int x,int y){
    link(findset(x),findset(y));
  }

  void link(int x,int y){
    if (rank[x] > rank[y]){
      p[y]=x;
    }else {
      p[x]=y;
      if (rank[x] == rank[y])rank[y]++;
    }
  }
  int findset(int x){
    if (x != p[x])p[x] = findset(p[x]);
    return p[x];
  }
};

int is_intersected_circle(P a,P b,double r1,double r2){
  double d =abs(a-b);
  if (d<eps&&abs(r1-r2)<eps)return 3;
  if (d+r2 < r1)return 0;
  if (d+r1 < r2)return 1;

  if (d > r1+r2)return 4;

  return 2;
}

inline double calc_r(double z,double r){
  if (z < 0)z*=-1;
  return sqrt(r*r-z*z);
}



double bsearch(P a,P b,double az,double bz,double ar,double br,double r,double l,
	       bool islower){
  double mid;
  while(l < r+eps){
    mid = (r+l)/2;
    if (islower){
      if (is_intersected_circle(a,b,calc_r(az-mid,ar),calc_r(bz-mid,br))==2)r=mid-eps;
      else l=mid+eps;
    }else {
      if (is_intersected_circle(a,b,calc_r(az-mid,ar),calc_r(bz-mid,br))==2)l=mid+eps;
      else r=mid-eps;
    }
  }
  return mid;
}

int is_intersected_sphere(Point a,Point b,double r1,double r2){
  double d =sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
  if (d<eps&&abs(r1-r2)<eps)return 3;
  if (d+r2 < r1)return 0;
  if (d+r1 < r2)return 1;
  if (d > r1+r2)return 4;
  return 2;
}

double compute_z(Point a,Point b,double r1,double r2){
  double l,m,n;
  double d =sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z)); 
  double z;
  l=(d*d-r2*r2+r1*r1)/(2*d);
  z = a.z + (b.z-a.z)*l/d;
  return z;
}

bool is_contain_center_in_sphere(Point a,Point b,double r1){
  double d =sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z)); 
  if (d < r1+eps)return true;
  return false;
}

bool is_contain_center_in_circle(P a,P b,double r1){
  if (isnan(r1))return false;
  double d = abs(a-b);
  if (d < r1 + eps)return true;
  return false;
}

bool is_contain_on_intersection(P a,P b,double ra,double rb){
   return is_contain_center_in_circle(a,b,ra)||is_contain_center_in_circle(b,a,rb);
}

void solve(int n,Point *in,double *r){
  vector<pair<double,int> > ans;
  rep(i,n){
    ans.pb(mp(in[i].z-r[i],1));
    ans.pb(mp(in[i].z+r[i],0));
  }

  rep(i,n){
    REP(j,i+1,n){
      int tmp = is_intersected_sphere(in[i],in[j],r[i],r[j]);
      if (is_intersected_sphere(in[i],in[j],r[i],r[j]) == 2){
	double z = compute_z(in[i],in[j],r[i],r[j]);
	double right,left;
	right=z;
	left=max(in[i].z-r[i],in[j].z-r[j]);
	double tmp =bsearch(P(in[i].x,in[i].y),P(in[j].x,in[j].y),in[i].z,in[j].z,
			    r[i],r[j],right,left,true); 
	ans.pb(mp(tmp,1));//start of intersection
	right=min(in[i].z+r[i],in[j].z+r[j]);
	left=z;
	tmp = bsearch(P(in[i].x,in[i].y),P(in[j].x,in[j].y),in[i].z,in[j].z,
		      r[i],r[j],right,left,false);
	ans.pb(mp(tmp,0));//start of intersection
      }
    }
  }


  int component=0;
  sort(ALL(ans));
  DisjointSet dj(n);
  vector<int >ret;
  rep(k,ans.size()){
    int tmp=0;
    double z = ans[k].first+eps;
    rep(i,n)dj.makeset(i);

    //cout <<k <<" " << z <<" " << ans[k].second <<  endl;



    rep(i,n){
      if (isnan(calc_r(in[i].z-z,r[i])))continue;
      REP(j,i+1,n){
	if (isnan(calc_r(in[j].z-z,r[j])))continue;	
	if (
	    is_contain_on_intersection(
				       P(in[i].x,in[i].y),
				       P(in[j].x,in[j].y),
				       calc_r(in[i].z-z,r[i]),
				       calc_r(in[j].z-z,r[j]))
	    ||
	    is_intersected_circle(P(in[i].x,in[i].y),
				  P(in[j].x,in[j].y),
				  calc_r(in[i].z-z,r[i]),
				  calc_r(in[j].z-z,r[j])) == 2
	    
	    )dj.merge(i,j);
      }
    }
    
    rep(i,n){
      if (isnan(calc_r(in[i].z-z,r[i])))continue;
      if (i == dj.findset(i))tmp++;
    }

    /*
      rep(i,n){
      if (isnan(calc_r(in[i].z-z,r[i])))cout <<"= ";
      else cout << dj.findset(i) <<" ";
    }
    cout << endl;
    */    

    
    if (tmp > component)ret.pb(1);//cout << 1;
    else if (tmp < component)ret.pb(0);//cout << 0;
    

    component=tmp;
  }

  cout << ret.size() << endl;
  rep(i,ret.size()){
    cout << ret[i];
  }
  cout << endl;

      /*
  sort(ALL(ans));
  cout << ans.size() << endl;
  rep(i,ans.size()){
    cout << ans[i].second;
  }
  cout << endl;
      */
}


main(){
  int n;
  while(cin>>n && n){
    double r[n];
    Point in[n];
    rep(i,n){
      cin>>in[i].x>>in[i].y>>in[i].z >>r[i];
    }
    solve(n,in,r);
  }
}