計算幾何高階 掃瞄線

2021-08-20 23:08:02 字數 3593 閱讀 3290

關於掃瞄線的題目,做法我感覺應該比較容易看出來,但是其中的性質很難找。只要結合題目的背景來找出它其中的數學性質,題目就能迎刃而解了。

a - coneology

題意:乙個笛卡爾座標系中有許多的圓,有些圓包含其他的圓,一定不存在相交的圓。問有多少個沒有被任乙個圓包含的圓。

4e4的資料量肯定不允許我們暴力,暴力實際上有許多沒必要的計算。因為根據他們的位置關係,有些圓之間不相交能推出另個圓也不和這個圓相交。所以我們得利用他們的位置關係來計算,這裡也就是用到了掃瞄線。

從左往右掃瞄,左端點進set,右端點出set。並且set是到目前為止右端點還沒到的不相交的圓的集合。

碰到左端點的時候,就得將該圓與set裡面的圓進行包含判斷。而這個判斷也並不是與所有set裡的圓都得判斷一遍,我們只需找到set裡面y第乙個大於等於它的和y第乙個小於它的兩個圓,與其判斷即可。大家可以畫畫圖想一想。

碰到右端點將set裡面的圓刪除即可。

所以我們要在set裡面存y值及下標。

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

const

int maxn=400005;

const

double eps=1e-3;

int sgn(double x)

double r[maxn],x[maxn],y[maxn];

vector

double,int> >v;

setdouble,int> >s;

vector

ans;

bool check(int idx1,int idx2)

int main()

sort(v.begin(),v.end());

for(int i=0; iint idx=v[i].second%n;

if(v[i].second>=n)

else

}sort(ans.begin(),ans.end());

printf("%d\n",ans.size());

for(int i=0; iif(i)printf(" ");

printf("%d",ans[i]+1);

}puts("");

return

0;}

b - moo****t

求最小圓距。

直接講思路吧,畫了半天圖總感覺怪怪的。。

求這個圓距,我們可以二分距離num,然後判斷是否有圓相交。

判斷是否有圓相交可以用兩條掃瞄線,乙個列舉左邊界i,乙個列舉右邊界j。

當x[i]-r[i]-num<=x[j]+r[j]+num,則判斷i圓並將i圓放入set裡,否則將i圓在set裡刪掉。

這樣寫可以過題,但是有bug。

大家可以看看這個樣例

1 3

-10 20 1

0 0 10

30 40 39

所以我們需要在圓刪除之前再判斷一次。

#include

using

namespace

std;

const

int maxn=50005;

int x[maxn],y[maxn],r[maxn];

int rl[maxn],rr[maxn],ru[maxn];

bool cmpl(int a,int b)

double dis2(int a,int b)

sets;

typedef

set::iterator it;

bool check2(int num,double add)

if(itor!=s.begin())

return0;}

int n;

bool check(double num)

else

}return

false;

}void solve()

printf("%.6f\n",mid*2);

}int main()

sort(rl,rl+n,cmpl);

sort(rr,rr+n,cmpr);

sort(ru,ru+n,cmpu);

for(int i=0;i之後會更詳細的講解該題。。

c - light and shadow

這題一開始理解錯題意了,該題意為能照到的棍子的個數。

由於題目已經說了,不存在兩根棍子相交,所以距離點光源最近的棍子不管點光源怎麼射,它都是最前面的。所以我們可以以點光源為原點,以極座標排序,逆時針掃一下。記錄一下每條棍子的起點和終點,當遇到棍子的起點時,我們可以以原點和它的起點作一條射線,計算射線與棍子的交點距原點的距離來重新將set裡面的棍子排序。

當然這裡有乙個特別的地方,就是與射線(-1,0)相交的棍子它們的起點在第二象限,按照我們那種排序方式它會在最後才被加進去,所以我們得預先把它裝進來。

#include

using

namespace

std;

const

int maxn=10005;

const

double eps=1e-8;

int sgn(double x)

struct point

point(){}

point operator-(const point &b)const

double

operator*(const point &b)const

double

operator^(const point &b)const

bool

operator

<(const point &b)const

};point cur;

typedef

const point cp;

point intersection(cp &u1,cp &u2,cp &v1,cp &v2)

double dis(point a)

struct line

line(){}

bool

operator

<(const line &b)const

}lines[maxn*2];

bool cmp(line a,line b)

int n;

void input()

sort(lines,lines+2*n,cmp);

for(int i=0;i<2*n;i++)

}for(int i=0;i<2*n;i++)

else

if(!s.empty())

}int ans=0;

for(int i=0;iif(ok[i])ans++;

printf("%d\n",ans);

}int main()

return

0;}

b題實際上我還沒有想清楚,剛剛寫的**還沒來得及執行電腦就藍屏了。。。等想清楚了會更新該部落格的。

poj2932 掃瞄線 平面幾何

挑戰程式設計p258 將圓的x左邊左端和右端儲存起來 for int i 0 i排序 sort events.begin events.end 判斷 在本題中圓只有兩種情況 包含與不包含 for int i 0 i iterator it outers.lower bound make pair y...

poj2932 掃瞄線 平面幾何

挑戰程式設計p258 將圓的x左邊左端和右端儲存起來 for int i 0 i排序 sort events.begin events.end 判斷 在本題中圓只有兩種情況 包含與不包含 for int i 0 i iterator it outers.lower bound make pair y...

P5490 模板 掃瞄線 掃瞄線

題目描述 求 n 個矩形的面積並。輸出格式 一行乙個正整數,表示 n 個矩形的並集覆蓋的總面積。発生 線段樹開小了,因為n變成了兩倍,線段樹就得開4 2 8倍 對每一根掃瞄線,維護所截得的長度,每次乘以兩根掃瞄線高度差就得到了面積並 截得長度用線段樹維護即可 注意線段樹需要離散化 include i...