【题意】
给出n个圆(n<=20),求有多少个不被圆覆盖的封闭区域
【输入】
第一行t,表示有t组数据
每组数据第一行为n表示有多少个圆
接下来n行分别描述n个圆,每行为x,y,r
【输出】
对于每组数据,输出有几个不被圆覆盖的封闭区域
Sample Input
2 4 100 100 20 100 135 20 135 100 20 135 135 20 1 10 10 40
Sample Output
1 0
离散化
07年论文有讲(高逸涵《与圆有关的离散化方法》)
对于任意一行y=k,都可以求出来不被圆覆盖的区间
观察可以很轻易的发现,区域连通性的变化,其实都发生在圆与圆交点所在的那一行或者是圆的上下处
我们将这些行称之为事件点
对于每个事件点,我们求他上下稍微偏移一点的区间
因为不在通过事件点,连通性不会变化
所以如果从下往上扫描的话,对于一个事件点的下偏移那行,跟上个事件点上偏移的那行,连通性是完全相同的
当然区间数也相同
接下来就是从一个事件点的下偏移转移到上偏移
如果他们之间区间有交集,那么这两个区间属于同一个联通块
一旦事件点下偏移有一个联通块没有上偏移的区间继承,那么说明有一个封闭的区间
程序写的十分乱。
program poj1688; const esp:extended=1e-8; type line=record l,r:extended; end; node=record x:extended; incr:boolean; end; var n,i,j,k,w,t,tot,all,total,o,ans,xx,oo,count:longint; x,y,r:array [0..21] of longint; event:array [0..601] of extended; xl:array [0..61] of node; temp:node; ind:array [0..10001] of line; own:array [0..10001] of longint; sum:array [0..1] of longint; dl:array [0..1,0..10001] of longint; yes:array [0..10001] of boolean; root,next,point:array [0..10001] of longint; procedure swap_int (var a,b:longint); var i:longint; begin i:=a; a:=b; b:=i; end; procedure swap_dou (var a,b:extended); var i:extended; begin i:=a; a:=b; b:=i; end; procedure solve (i,j:longint); var left,right,t,mid,leftr,rightr:extended; begin t:=y[j]+(y[i]-y[j])*r[j]/(r[i]+r[j]); left:=y[j]-r[j]; if y[i]-r[i]>left then left:=y[i]-r[i]; right:=t; repeat mid:=(left+right)/2; leftr:=sqrt(sqr(r[j])-sqr(mid-y[j])); rightr:=sqrt(sqr(r[i])-sqr(mid-y[i])); if (x[j]+leftr<x[i]-rightr) or (x[j]-leftr>x[i]+rightr) then left:=mid else right:=mid; until abs(left-right)<1e-8; inc(tot); event[tot]:=left; left:=t; right:=y[j]+r[j]; if y[i]+r[i]<right then right:=y[i]+r[i]; repeat mid:=(left+right)/2; leftr:=sqrt(sqr(r[j])-sqr(mid-y[j])); rightr:=sqrt(sqr(r[i])-sqr(mid-y[i])); if (x[j]+leftr<x[i]-rightr) or (x[j]-leftr>x[i]+rightr) then right:=mid else left:=mid; until abs(left-right)<1e-8; inc(tot); event[tot]:=left; end; procedure qsort (s,e:longint); var i,j:longint; k:extended; begin if s>=e then exit; i:=s; j:=e; k:=event[(s+e) div 2]; while i<=j do begin while (i<=j)and(event[i]<k) do inc(i); while (i<=j)and(event[j]>k) do dec(j); if i>j then break; swap_dou(event[i],event[j]); inc(i); dec(j); end; qsort(s,j); qsort(i,e); end; procedure connect (s,e:longint); begin inc(oo); point[oo]:=e; next[oo]:=root[s];; root[s]:=oo; end; procedure dfs (now:longint); var i:longint; begin yes[now]:=true; i:=root[now]; while i<>0 do begin if not yes[point[i]] then begin own[point[i]]:=own[now]; if point[i]>=dl[o,1] then inc(count); dfs(point[i]); end; i:=next[i]; end; end; procedure merge (now:longint); var i,j,k:longint; a,b,t:extended; begin o:=1-o; t:=event[now]-esp; total:=0; for i:=1 to n do if sqr(y[i]-t)<sqr(r[i]) then begin inc(total); xl[total].x:=x[i]-sqrt(sqr(r[i])-sqr(y[i]-t)); xl[total].incr:=true; inc(total); xl[total].x:=x[i]+sqrt(sqr(r[i])-sqr(y[i]-t)); xl[total].incr:=false; end; for i:=1 to total-1 do for j:=i+1 to total do if xl[i].x>xl[j].x then begin temp:=xl[i]; xl[i]:=xl[j]; xl[j]:=temp; end; k:=0; w:=1; for i:=1 to total do if xl[i].incr then begin if k=0 then begin ind[dl[1-o,w]].r:=xl[i].x; inc(w); end; inc(k); end else begin dec(k); if k=0 then ind[dl[1-o,w]].l:=xl[i].x; end; t:=event[now]+esp; total:=0; for i:=1 to n do if sqr(y[i]-t)<sqr(r[i]) then begin inc(total); xl[total].x:=x[i]-sqrt(sqr(r[i])-sqr(y[i]-t)); xl[total].incr:=true; inc(total); xl[total].x:=x[i]+sqrt(sqr(r[i])-sqr(y[i]-t)); xl[total].incr:=false; end; for i:=1 to total-1 do for j:=i+1 to total do if xl[i].x>xl[j].x then begin temp:=xl[i]; xl[i]:=xl[j]; xl[j]:=temp; end; sum[o]:=1; inc(all); dl[o,1]:=all; ind[all].l:=-1000000; k:=0; for i:=1 to total do if xl[i].incr then begin if k=0 then ind[all].r:=xl[i].x; inc(k); end else begin dec(k); if k=0 then begin inc(all); inc(sum[o]); dl[o,sum[o]]:=all; ind[all].l:=xl[i].x; end; end; ind[all].r:=1000000; for i:=1 to sum[o] do yes[dl[o,i]]:=false; for i:=1 to sum[1-o] do yes[dl[1-o,i]]:=false; for i:=1 to sum[1-o] do root[dl[1-o,i]]:=0; oo:=0; for i:=1 to sum[1-o] do for j:=1 to sum[1-o] do if (i<>j)and(own[dl[1-o,i]]=own[dl[1-o,j]]) then begin connect(dl[1-o,i],dl[1-o,j]); connect(dl[1-o,j],dl[1-o,i]); end; for i:=1 to sum[1-o] do for j:=1 to sum[o] do if not ((ind[dl[1-o,i]].l>ind[dl[o,j]].r)or(ind[dl[1-o,i]].r<ind[dl[o,j]].l)) then begin connect(dl[1-o,i],dl[o,j]); connect(dl[o,j],dl[1-o,i]); end; for i:=1 to sum[1-o] do if not yes[dl[1-o,i]] then begin count:=0; dfs(dl[1-o,i]); if count=0 then inc(ans); end; for i:=1 to sum[o] do if not yes[dl[o,i]] then begin inc(xx); own[dl[o,i]]:=xx; end; end; begin read(t); while t<>0 do begin fillchar(root,sizeof(root),false); fillchar(next,sizeof(next),0); read(n); for i:=1 to n do read(x[i],y[i],r[i]); for i:=1 to n-1 do for j:=i+1 to n do if x[i]-r[i]>x[j]-r[j] then begin swap_int(x[i],x[j]); swap_int(y[i],y[j]); swap_int(r[i],r[j]); end; tot:=0; for i:=1 to n do begin inc(tot); event[tot]:=y[i]-r[i]; inc(tot); event[tot]:=y[i]+r[i]; end; for i:=1 to n-1 do for j:=i+1 to n do if sqr(x[i]-x[j])+sqr(y[i]-y[j])<sqr(r[i]+r[j]) then solve(i,j); qsort(1,tot); event[0]:=-10000000000; o:=0; sum[o]:=1; all:=1; ans:=0; xx:=1; dl[o,1]:=1; own[1]:=1; ind[1].l:=-1000000; ind[1].r:=1000000; for i:=1 to tot do if event[i]-event[i-1]>esp then merge(i); writeln(ans); dec(t); end; end.