题意:给定n对点对(a[i][0],a[i][1]),从每对点对中取一个点,问构成凸包的面积期望值。
方法:时限较长,可以采用暴力的方法。
若一条边在凸包上,则需要所有的点都在它的左边。
考虑剩于n-2对点对:
若两个点都在右边,则概率为0;
若只有一个点在左边,则概率乘以0.5;
若两个点都在左边,则概率为1;
根据乘法原理,可以算出该边在凸包上的概率。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <math.h>
using namespace std;
typedef long long ll;
const int N=1005;
struct node{
ll x,y;
node(){}
node(ll _x,ll _y):x(_x),y(_y){}
node operator - (const node &B)const{
return node(x-B.x,y-B.y);
}
ll operator * (node B){
return x*B.y-y*B.x;
}
}a[N][2];
int n;
void work(){
while(~scanf("%d",&n)){
for(int i=0;i<n;i++)
scanf("%I64d%I64d%I64d%I64d",&a[i][0].x,&a[i][0].y,&a[i][1].x,&a[i][1].y);
double ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)if(i!=j){
for(int t=0;t<2;t++){
for(int s=0;s<2;s++){
node *x,*y;
x=&a[i][t];
y=&a[j][s];
ll temp=*x * *y;
bool flag=true;
int l,r;
int cnt=0;
for(int k=0;k<n;k++)if(k!=i&&k!=j){
l=r=0;
if((*y - *x)*(a[k][0]- *x)>0)l++;
else r++;
if((*y - *x)*(a[k][1]- *x)>0)l++;
else r++;
if(r==2){
flag=false;break;//剪枝一下,大部分都会退出循环
}
else if(l==1)cnt++;
}
if(flag)
ans+=0.125*temp*pow(0.5,cnt);
}
}
}
}
printf("%.10lf\n",ans);
}
}
int main(){
//freopen("data_in.txt","r",stdin);
work();
return 0;
}
该方法跑了3808ms,其实还有更优的方法,但我还没想通。