非常难的计算几何题,我认为几乎不可做
我们考虑每四个点组成的四边形,如果是凹四边形,那么四个点中每三个构成的四个园中只有一个会包含第四个点,所以贡献是1,如果是凸四边形,则有两个,贡献是2
(注:这幅图片来自csdn“我是傻叉”的博客)
这样
ans=Num凸四边形×2+Num凹四边形C3n(圆的总个数)
a
n
s
=
N
u
m
凸
四
边
形
×
2
+
N
u
m
凹
四
边
形
C
n
3
(
圆
的
总
个
数
)
考虑到
Num凸四边形+Num凹四边形=C4n
N
u
m
凸
四
边
形
+
N
u
m
凹
四
边
形
=
C
n
4
,所以只要算凹四边形的个数就可以了
凹四边形的实质是有一个点被其他三个点所形成的三角形覆盖
我们枚举被覆盖的点i,然后计算有多少个三角形覆盖这个点
注意到
Num合法的三角形=Num覆盖当前点的三角形+Num不覆盖当前点的三角形=C4n−1
N
u
m
合
法
的
三
角
形
=
N
u
m
覆
盖
当
前
点
的
三
角
形
+
N
u
m
不
覆
盖
当
前
点
的
三
角
形
=
C
n
−
1
4
,所以我们只要算不覆盖当前点的三角形数就可以了
我们考虑把所有的点按照极坐标排序,也就是以这个点与当前点连线作为终边的角的大小排序
我们再枚举一个点j,然后逆时针方向找到最远的点pt,使得pt与j的夹角小于180度,那么j+1~pt的店当中任取两个与j构成的三角形都不包含i
然后我们发现随着j的移动,pt的移动是单调的,所以可以利用two pointers之类的思想转一圈
于是总复杂度
O(n2logn)
O
(
n
2
l
o
g
n
)
,
logn
l
o
g
n
来自排序
*这道题卡精度,卡常
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;
const LL MOD=1e9+7;
const LL LINF=2e16;
const int INF=2e9;
const int magic=348;
const double eps=1e-15;
const long double pi=acos(-1);
inline int getint()
{
char ch;int res;bool f;
while (!isdigit(ch=getchar()) && ch!='-') {}
if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
while (isdigit(ch=getchar())) res=res*10+ch-'0';
return f?res:-res;
}
int n;
Pair a[2048];
struct node
{
int x,y;
long double ang;
}b[4048];int tot;
int cmpx,cmpy;
inline int calc_region(int x,int y,int xx,int yy)
{
int dx=xx-x,dy=yy-y;
if (dx>0 && dy>=0) return 1;
if (dx<=0 && dy>0) return 2;
if (dx<0 && dy<=0) return 3;
if (dx>=0 && dy<0) return 4;
}
inline long double calc_angle(int x,int y,int xx,int yy)
{
int pt=calc_region(x,y,xx,yy);
if (x==xx) return (pt==2?90:270);
if (y==yy) return (pt==1?0:180);
long double k=(long double)(y-yy)/(x-xx);
long double res=atan(k)/pi*180;
if (pt==1) return res;
if (pt==2) return res+180;
if (pt==3) return res+180;
if (pt==4) return res+360;
}
inline bool cmp(node x,node y)
{
return y.ang-x.ang>eps;
}
inline long double judge(int ind1,int ind2)
{
return (b[ind1].ang-b[ind2].ang>eps?b[ind1].ang-b[ind2].ang:b[ind1].ang-b[ind2].ang+360);
}
inline LL C(int x,int y)
{
if (x<y) return 0;
LL res=1;int i;
for (i=x;i>=x-y+1;i--) res*=i;
for (i=y;i;i--) res/=i;
return res;
}
int main ()
{
int i,j;n=getint();
for (i=1;i<=n;i++) a[i].x=getint(),a[i].y=getint();
long double ans=0;
for (i=1;i<=n;i++)
{
cmpx=a[i].x;cmpy=a[i].y;tot=0;
for (j=1;j<=n;j++)
{
if (i==j) continue;
b[++tot]=node{a[j].x,a[j].y,calc_angle(cmpx,cmpy,a[j].x,a[j].y)};
}
sort(b+1,b+tot+1,cmp);
for (j=tot+1;j<=tot*2;j++) b[j]=b[j-tot];
int pt=1;LL cnt=0;
for (j=1;j<=tot;j++)
{
pt=max(pt,j+1);
while (judge(pt,j)<180 && pt<j+tot) pt++;pt--;
cnt+=C(pt-j,2);
}
cnt=C(n-1,3)-cnt;ans+=cnt;
}
ans=ans+(C(n,4)-ans)*2;ans/=C(n,3);ans+=3;
printf("%.6Lf\n",ans);
return 0;
}