1. 程式人生 > >POJ 2932 Coneology計算最外層圓個數

POJ 2932 Coneology計算最外層圓個數

image 假設 計算 什麽是 圓心 代碼 amp 什麽 題意

平面上有n個兩兩沒有公共點的圓,i號圓的圓心在(xi,yi),半徑為ri,編號從1開始。求所有最外層的,即不包含於其他圓內部的圓。輸出符合要求的圓的個數和編號。n<=40000.

(註意此題無相交相切!!!)
工具:掃描線+set

技術分享圖片

中心思想:
邊界分左右端點,如圖,當掃描線與k號圓左端點相切,之前用set維護一個y縱坐標的二叉樹,那我們在二叉樹中查找離k號圓縱坐標最近的上下兩個圓(A,B),讓k與A,B判是否內含即可,為什麽是AB?假設有C點(離k遠一些)包含k,但A不包含k,那麽一定有A,C相交,這不符合題意。
之後,當掃到右端點,從set中刪掉這個圓(即圖中的D,因為它對後面k的判斷沒卵關系,而且還可能阻礙A,B)

上代碼:

typedef pair<double,int>P;

struct node{
double x,y,r;
}nod;

bool inside(int a,b){//判斷a是否在b中,半徑大於圓心距
double dx=node[a].x-node[b].x,dy=node[a].y-node[b].y;
return dx*dx+dy*dy-node[b].r*node[b].r<=eps;
}

void solve(){
vector<P>point;
set<P>outer;//記錄與當前掃描線相交的最外層圓集合
vector<int>ans;//真正存儲最外層圓集合 For(i,1,n){ point.pb(P(nod[i].x-nod[i].r,i));//記錄左端點 point.pb(P(nod[i].x+nod[i].r,i+n));//記錄右端點 } sort(point+1,point+1+n); For(i,0,point.size()-1){ int id=point[i].sd; if(point[i].sd<n){//掃到左端點 set<P>::iterator it=outer.lower_bound(P(nod[id].y,id));//二分找A,B
if(it!=outer.begin()&&inside(id,it->sd))continue; if(it!=outer.end()&&inside(id,(--it)->sd))continue; ans.pb(P(nod[id].y,id)); outer.insert(P(nod[id].y,id)); }else outer.erase(P(node[id].y,id)); //掃到右端點,刪掉 } sort(ans.begin(),ans.end());

POJ 2932 Coneology計算最外層圓個數