传送门:hihocoder1225
把每个凸包的面积三角剖分,划分成每个三角形的有向面积之和。
转化成统计每条边作为凸包边的概率 × \times ×该边与基点构成三角形有向面积。
假设凸包边为逆时针指向,所以对于当边 i , j i,j i,j右侧没有点时,该边即为凸包边。若存在一组的两个点都在 i , j i,j i,j右侧,则概率为 0 0 0,否则概率为 1 2 一 组 中 有 一 个 点 在 i , j 右 侧 的 组 数 \frac 12 ^{一组中有一个点在i,j右侧的组数} 21一组中有一个点在i,j右侧的组数,最后还要乘上选中 i , j i,j i,j的概率为 1 4 \frac 14 41。
枚举起点,极角扫描将复杂度优化到 O ( n 2 log n ) O(n^2\log n) O(n2logn)
这份代码被卡精度了QWQ。卡不动弃疗了。
算几想题一分钟,写题写一天
#include
typedef double db;
using namespace std;
const db pi=acos(-1.0);
const int N=2100;
int n,m,cnt[N],cot,num;
db ans,pw[N];
struct P{
db x,y;
P(db x_=0.0,db y_=0.0):x(x_),y(y_){};
inline P operator +(const P&ky){return P(x+ky.x,y+ky.y);}
inline P operator -(const P&ky){return P(x-ky.x,y-ky.y);}
inline db operator ^(const P&ky){return x*ky.y-y*ky.x;}
}p[N],st;
struct Q{
P pt;db ag;int id;
Q(){};
Q(P pt_,int id_){pt=pt_;id=id_;ag=atan2(pt.y,pt.x);}
bool operator<(const Q&ky)const{return ag<ky.ag;}
}q[N];
inline void ins(int x){if((++cnt[x])==2) cot++;num++;}
inline void del(int x){if((--cnt[x])==1) cot--;num--;}
inline db cal(int x,int op)
{
int i,j,pos;db re=0.0,res;
st=p[x+op*n];m=cot=num=0;memset(cnt,0,sizeof(cnt));
for(i=1;i<=n;++i) if(i^x) q[++m]=Q(p[i]-st,i),q[++m]=Q(p[i+n]-st,i);
sort(q+1,q+m+1);
for(j=m;j>0 && q[j].ag>0;--j) ins(q[j].id);pos=++j;
for(i=1;i<=m && q[i].ag<=0;++i){
for(;j<=m && q[j].ag-q[i].ag<=pi;++j) del(q[j].id);
if(!cot) re+=(st^(q[i].pt+st))*pw[num-cnt[q[i].id]];
ins(q[i].id);
}
for(;j<=m;++j) del(q[j].id);j=1;
for(i=pos;i<=m;++i){
for(;j<pos && q[i].ag-q[j].ag>=pi;++j) del(q[j].id);
if(!cot) re+=(st^(q[i].pt+st))*pw[num-cnt[q[i].id]];
ins(q[i].id);
}
return re;
}
int main(){
int i,j,x,y;
scanf("%d",&n);pw[0]=1.0;
for(i=1;i<=n;++i){
scanf("%d%d",&x,&y);p[i]=P(x,y);
scanf("%d%d",&x,&y);p[i+n]=P(x,y);
pw[i]=pw[i-1]*0.5;
}
for(i=1;i<=n;++i) ans+=cal(i,0)+cal(i,1);
printf("%.10lf",(double)(ans/8.0));
return 0;
}