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