題目描述:
個人,每個人個旗子座標爲 ,
點被最小的 佔領,的範圍爲,求每個人的佔領面積。
題目分析:
記 ,,同理。
相當於對於滿足 的 有 。那麼 的佔領面積相當於半平面交。
確定半平面交直線方向向量的方法:
在直線的法向量 一邊的點一定滿足
(對於任意點滿足,有)
如果令半平面交取左手邊(逆時針),那麼 對應的方向向量就是法向量逆時針轉 ,即
然後再解出一個滿足的 就可以確定這條直線了。
半平面交一次轉超過隨便舉反例,要在外面框個矩形,每次最多轉,最後少於3條線就無解。
舉幾個例子加深理解:
Code:
#include<bits/stdc++.h>
#define maxn 115
using namespace std;
const double eps = 1e-6;
int T,n,m;
double sx[maxn],sy[maxn],sx2[maxn],sy2[maxn];
int sgn(double x){return x>eps?1:x<-eps?-1:0;}
struct Pt{
double x,y;
Pt(double x=0,double y=0):x(x),y(y){}
Pt operator + (const Pt &p)const{return Pt(x+p.x,y+p.y);}
Pt operator - (const Pt &p)const{return Pt(x-p.x,y-p.y);}
Pt operator * (const double &t)const{return Pt(x*t,y*t);}
double operator * (const Pt &p)const{return x*p.y-y*p.x;}
}p[maxn];
struct Line{
Pt p,v; double ang;
Line(Pt p=0,Pt v=0):p(p),v(v),ang(atan2(v.y,v.x)){}
bool operator < (const Line &L)const{return sgn(ang-L.ang)?ang<L.ang:v*(L.p-p)<=0;}
}L[maxn],q[maxn];
int cnt,l,r;
bool Onleft(Pt p,Line L){return L.v*(p-L.p)>0;}
Pt Inter(Line a,Line b){return a.p+a.v*((b.v*(a.p-b.p))/(a.v*b.v));}
double HalfPlane(){
sort(L+1,L+1+cnt);
q[l=r=1]=L[1];
for(int i=2;i<=cnt;i++) if(sgn(L[i].ang-L[i-1].ang)){
while(l<r&&!Onleft(p[r-1],L[i])) r--;
while(l<r&&!Onleft(p[l],L[i])) l++;
q[++r]=L[i],p[r-1]=Inter(q[r-1],q[r]);
}
while(l<r-1&&!Onleft(p[r-1],q[l])) r--;
if(r-l<=1) return 0;
p[r]=Inter(q[l],q[r]);
double ans=0;
for(int i=l;i<=r;i++) ans+=p[i]*p[i+1>r?l:i+1];
return ans/2;
}
int main()
{
scanf("%d",&T);
for(int t=1;t<=T;t++){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) sx[i]=sy[i]=sx2[i]=sy2[i]=0;
for(int i=1,x,y;i<=n;i++) for(int j=1;j<=m;j++){
scanf("%d%d",&x,&y);
sx[i]+=x,sy[i]+=y,sx2[i]+=x*x,sy2[i]+=y*y;
}
printf("Case #%d: ",t);
for(int i=1;i<=n;i++){
L[cnt=1]=Line(Pt(0,0),Pt(1,0)),L[++cnt]=Line(Pt(4095,0),Pt(0,1));
L[++cnt]=Line(Pt(4095,4095),Pt(-1,0)),L[++cnt]=Line(Pt(0,4095),Pt(0,-1));
for(int j=1;j<=n;j++) if(i!=j){
double A=-2*(sx[i]-sx[j]),B=-2*(sy[i]-sy[j]),C=sx2[i]-sx2[j]+sy2[i]-sy2[j];
if(sgn(A)) L[++cnt]=Line(Pt(-C/A,0),Pt(-B,A));
else L[++cnt]=Line(Pt(0,-C/B),Pt(-B,A));
}
printf("%d%c",(int)round(HalfPlane()),i==n?10:32);
}
}
}