Problem:
Problem 07: Crop Circle

アルゼンチンの広大な農地に突如ミステリーサークルが出没した。ミステリーサークルは重なっているもの、ポツンとあるもの、大きいもの、小さいものと合計 n 個確認された。

あるミステリーハンターが空中からミステリーサークルの全体像を撮影しようと試みたところ、各円の輪郭がはっきりしていなかったため、映像にその美しい模様を映し出すことが難しいことが分かった。

そこで、そのミステリーハンターは輪郭に沿って特殊素材の紐を設置し、輪郭を強調する提案をした。

紐を設置する部分は、あるミステリーサークルの円周上で、他のどのミステリーサークルにも含まれない部分である。

撮影隊は必要な紐の長さを計測するために、プログラムの作成をあなたに依頼した。各ミステリーサークルの中心座標と半径を入力し、設置する紐の長さを報告するプログラムを作成せよ。

参考として入出力例の１つ目と２つ目のケースをそれぞれ図１、図２に示す。紐の部分が太い線で示されている。

図１

図２

Input

入力として複数のデータセットが与えられる。各データセットは以下の形式で与えられる：

n　（ミステリーサークルの数：整数）

x1 y1 r1 　（1 個目のサークルの中心座標と半径：空白区切りの実数）

x2 y2 r2 　（2 個目のサークルの中心座標と半径：空白区切りの実数）

.

.

xn yn rn 　（n 個目のサークルの中心座標と半径：空白区切りの実数）

n が 0 のとき、入力の終わりを示す。

Output

各データセットに対して、紐の長さを１行に出力せよ。出力は 0.000001 以下の誤差を含んでもよい。

Constraints

n ≤ 100

-1000 ≤ xi, yi ≤ 1000

0 < ri ≤ 100

Sample Input

4
6 4 2
4 7 3
7 10 3
13 6 1
4
7 4 2
4 7 3
7 10 3
11 6 3
0

Output for the Sample Input

39.664699289572
45.627024663706

Solution in C (judge verdict: Time Limit Exceeded)

// AOJ 1047 Crop Circle
// 2018.3.7 bal4u

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

//#define getchar_unlocked()  getchar()
int in()
{
	int n = 0;
	int c = getchar_unlocked();
	if (c == '-') {
		c = getchar_unlocked();
		do n = (n<<3)+(n<<1) + (c & 0xf), c = getchar_unlocked();
		while (c >= '0');
		return -n;
	}
	do n = (n<<3)+(n<<1) + (c & 0xf), c = getchar_unlocked();
	while (c >= '0');
	return n;
}

typedef struct { double x, y; } PP;
typedef struct { PP p; double r; } C;

#define PI2     6.283185307179586476925286766559
#define EPS     1e-8
#define EQ(a,b) (fabs((a)-(b))<EPS)
PP d2p(double x, double y) { PP r; r.x = x, r.y = y; return r; }
PP vsub(PP p1, PP p2) { PP r; r.x = p1.x - p2.x, r.y = p1.y - p2.y; return r; }
double vabs(PP a) { return hypot(a.x, a.y); }
double dist(PP p1, PP p2) {	return vabs(vsub(p1, p2)); }

int intersectCC(C c1, C c2, PP *p1, PP *p2)
{
	double x1 = c1.p.x, y1 = c1.p.y, r1 = c1.r;
	double x2 = c2.p.x, y2 = c2.p.y, r2 = c2.r;
	double d = dist(d2p(x1, y1), d2p(x2, y2));
	double w, n, x, y, p, q;
	double u, v;

	u = r1+r2, v = fabs(r1-r2);

	if ((fabs(d-u) > EPS && d >= u) || fabs(v-d) > EPS && d <= v) return 0;
	w = ((r1*r1 - r2*r2)/d + d) / 2;
	n = sqrt(r1*r1 - w*w);
	x = x1 + (x2-x1)*w / d;
	y = y1 + (y2-y1)*w / d;
	p = (y2-y1)*n / d;
	q = (x2-x1)*n / d;

	p1->x = x+p, p2->x = x-p;
	p1->y = y-q; p2->y = y+q;
	if (fabs(d-u) <= EPS) return 1;
	if (d == r1+r2) return 1;
	return 2;
}

int n;
typedef struct { PP p; double a; } T;
T tbl[102][202]; int hi[102];
C   c[102]; char f[102];
int x[102], y[102], r[102];

int icheck(int a, int b)
{
	int dx = x[a]-x[b], dy = y[a]-y[b], dr = r[a]-r[b];
	return dx*dx + dy*dy <= dr*dr;
}

double angle(PP p, PP p0) { return atan2(p.y - p0.y, p.x - p0.x); }
int cmp(T *a, T *b) { if (EQ(a->a, b->a)) return 0; if (a->a <= b->a) return -1; return 1; }

int overlap(double *len, int id, int a, int b)
{
	int i;
	double ah, a1 = tbl[id][a].a, a2 = tbl[id][b].a;
	PP p0;

	ah = 0.5*(a1+a2);
	p0.x = c[id].p.x + c[id].r * cos(ah), p0.y = c[id].p.y + c[id].r * sin(ah);
	for (i = 0; i < n; i++) if (f[i] && i != id) {
		if (dist(p0, c[i].p) < c[i].r) return 1;
	}
	*len = c[id].r * (a2-a1);
	return 0;
}

int main()
{
	int i, j, k;
	PP p1, p2;
	double ans, a;

	while (n = in()) {
		for (i = 0; i < n; i++) {
			c[i].p.x = x[i] = in(), c[i].p.y = y[i] = in(), c[i].r = r[i] = in();
		}
		memset(f, 1, n);
		for (i = 0; i < n; i++) if (f[i]) for (j = 0; j < n; j++) if (f[j] && i != j) {
			if (r[i] >= r[j] && icheck(i, j)) f[j] = 0;
		}

		memset(hi, 0, n << 2);
		for (i = 0; i < n; i++) if (f[i]) {
			for (j = 0; j < n; j++) if (f[j] && j != i) {
				if (intersectCC(c[i], c[j], &p1, &p2) == 2) {
					k = hi[i]++, tbl[i][k].p = p1, tbl[i][k].a = angle(p1, c[i].p);
					k = hi[i]++, tbl[i][k].p = p2, tbl[i][k].a = angle(p2, c[i].p);
				}
			}
			qsort(tbl[i], hi[i], sizeof(T), cmp);
		}

		ans = 0;
		for (i = 0; i < n; i++) if (f[i]) {
			if (hi[i] == 0) ans += c[i].r * PI2;
			else {
				tbl[i][hi[i]] = tbl[i][0], tbl[i][hi[i]].a += PI2;
				for (j = 1; j <= hi[i]; j++) {
					if (!overlap(&a, i, j-1, j)) ans += a;
				}
			}
		}
		printf("%.8lf\n", ans);
	}
	return 0;
}