首先吐槽各种奇葩情况导致的错误...还有,此题是sgu上万里挑一的弱数据强思考题,点数只有8....啊啊啊啊啊啊啊啊啊啊是要推公式么...
不会公式...直接做了...当然首先膜拜金斌题解(虽有错误)...以下为题解,,,不是抄的...在自己做这题时发现其实有很多细节要处理...
首先将所有点都缩放在一个单位正方形(0,0)->(1,1)内
设p[i]为任取两点与凸包上第i条边相交的概率,那么直接由数学期望定义Σp[i]为相交边数的数学期望也是任取两点与任意边相交概率,
首先分情况讨论,取两点是有顺序性的
1:一个点在凸包内,一个在凸包外,概率为areapoly*(1-areapoly)*2
2:两个点都在凸包内概率为areapoly*areapoly*2/2=areapoly^2
3:两个点都在凸包外但与凸包相交,那么一定与凸包相交两条边
概率为((Σp[i])-(areapoly)*(1-areapoly)*2)/2,即与每条边相交期望减去与一条边相交期望得到与两条边相交期望,依据是E[A+B]=E[A]+E[B],那么再将期望除以相交的边数2,即得概率
将以上加起来就是最终答案,化简后ans=(Σp[i])/2+areapoly
那么就只需求每条边的概率了...
对于一条边,将其延长与单位正方形相交,那么任取两点与这条被延长的线相交的概率比较好算,只需一点在一侧,另一点在另一侧就可以了,设一侧面积为B,概率就是B*(1-B)*2
但是,这是任取两点与原线段与延长线相交概率总和,那么,我们必须去掉与延长线相交的概率...
如下图,对于一条有一端点处在边界上的线段,将其所在直线画出,正方形四个端点与其不在边界上的端点C所成的四条直线画出,
画出正方形与以上5条直线的交点,不考虑交点是否重合,将交点与点C所成向量极角排序,编号,这将正方形分成了10份,每份都是三角形
(2和3号点中间的是坐标单位点...和题目无关...)
首先是一定相交的概率,比如三角形12C与89C,直接就是两者面积相乘再乘2
对于每个三角形都有一个对角三角形比如23C和78C,12C与67C等.
对于12C与67C的情况,即其C点所对底边平行,很容易得到概率就是两者面积相乘再乘2再除以2
对于23C与78C的情况,即其C点所对底边垂直,就需要分析一下了.
如图:
考虑在78这条边上的点,设其到78C的高的垂足的距离为x,在23边上的点,设其到23C的高的垂足距离为y,78对应的高为hx,23边同样有hy
考虑题目中任取两点时,先在78C中取一点,再在23C中取一点,
取两个x值x1和x2,所对应的点与C点连线交于23边上,得其交点对应y值为y1和y2.
则对于x1,对答案贡献值应为三角形8x1C面积乘上2y1C面积,即(x1*hx/2)*(y1*hy/2)
同理x2贡献值为(x2*hx/2)*(y2*hy/2)但是两者贡献的答案有交集,考虑若对于x<=x1已经算出正确以去重的答案,对于x2,真正的贡献值应该为
((x2-x1)*hx/2)*(y2*hy/2)
再考虑微分思想,将x2-x1换成dx,那么总的答案即为(下表数字和字母为点的编号,l表示线段长度,如l[7S]表示7S的长度)
其中y可以用相似三角形算出来,即为
代换进去得:
积分得:
即为答案.
还有一种情况,就是所求线段的概率不是1C,而是6C,那么,所求概率为78C面积23C面积相乘(不乘2,因为固定了第一次取在78C中)减去以上所求答案
细节注意:三角形的最长边不一定是编号远离1号点的,在最上面的图中,三角形56C中,l[5C]>l[6C],还有第一次取在78C和第一次取在23C的答案是不一样的,即以上的x,y交换所得答案是不一样的
然后就可以算出题目所求答案了,
关于数据加强就是点数100000,且要先求凸包,还有range从(100,100)变为输入的(h,w),点坐标为实数
加强数据包:http://115.com/file/anm4qyc8
State:
原题Code:
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
typedef long double extended;
const extended eps=1e-12;
#define maxn 45
#define zero(x) (fabs(x)<eps)
#define equal(x,y) (zero(((x)-(y))))
struct point{extended x,y;};
const point ori={0,0};
const point matrix[4]={{0,0},{0,1},{1,1},{1,0}};
struct segment{point a,b;} seg[maxn];
struct line{extended a,b,c;};
extended posia=0,positot=0;
int segs=0;
int cmp(const void *p,const void *q)
{
point a=(*(point*)p),b=(*(point*)q);
if (equal(a.x,b.x))
if (equal(a.y,b.y)) return 0;
else if (a.y>b.y) return 1;
else return -1;
else if (a.x>b.x) return 1;
else return -1;
}
class classone
{
private:
int n,i;
point node[maxn];
extended cross(point a,point b)
{
return a.x*b.y-b.x*a.y;
}
public:
void initandgetsegment()
{
double a=0,b=0;
scanf("%d",&n);
for (i=1;i<=n;i++)
{
scanf("%lf%lf",&a,&b);
node[i].x=a/100;
node[i].y=b/100;
}
for (i=1;i<n;i++)
{
posia+=cross(node[i],node[i+1]);
segs++;
seg[segs].a=node[i];
seg[segs].b=node[i+1];
}
segs++;
seg[segs].a=node[n];
seg[segs].b=node[1];
posia+=cross(node[n],node[1]);
posia=fabs(posia);
posia/=2.0;
}
} class1;
class classtwo
{
private:
point dot[15],spot[15];
extended posis[maxn],area[15];
line l[5];
extended max(extended a,extended b)
{
if (a>b) return a;
return b;
}
extended min(extended a,extended b)
{
if (a<b) return a;
return b;
}
void swap(point &a,point &b)
{
static point tmp;
tmp=a;a=b;b=tmp;
}
void swap(line &a,line &b)
{
static line tmp;
tmp=a;a=b;b=tmp;
}
extended cross(point a,point b)
{
return a.x*b.y-b.x*a.y;
}
extended cross(point o,point a,point b)
{
a.x-=o.x,b.x-=o.x;
a.y-=o.y,b.y-=o.y;
return a.x*b.y-b.x*a.y;
}
extended trangle(point a,point b,point c)
{
return fabs(cross(a,b)+cross(b,c)+cross(c,a))/2.0;
}
void setline(line &u,point a,point b)
{
u=(line){0.0,0.0,0.0};
u.a=a.y-b.y;
u.b=b.x-a.x;
u.c=cross(a,b);
if (zero(u.a))
{
u.a=0.0;
u.c/=u.b;
u.b=1.0;
}
else
{
u.b/=u.a;
u.c/=u.a;
u.a=1.0;
}
if (u.a<0) u.a=-u.a,u.b=-u.b+0.0,u.c=-u.c+0.0;
}
bool para(line &u,line &v)
{
return (equal(u.a,v.a) && equal(u.b,v.b));
}
point getcommon(line u,line v)
{
if (zero(v.b)) swap(u,v);
point o;
o=ori;
if (zero(u.b))
{
o.x=-u.c/u.a;
o.y=-v.a/v.b*o.x-v.c/v.b;
}
else
{
static extended k1,k2,b1,b2;
k1=-u.a/u.b;
b1=-u.c/u.b;
k2=-v.a/v.b;
b2=-v.c/v.b;
o.x=(b1-b2)/(k2-k1);
o.y=k1*o.x+b1;
}
return o;
}
int qurant(point a)
{
if (a.x>0 && a.y>=0) return 1;
if (a.x<=0 && a.y>0) return 2;
if (a.x<0 && a.y<=0) return 3;
return 4;
}
bool cmp(point a,point b,point &o)
{
a.x-=o.x,a.y-=o.y;
b.x-=o.x,b.y-=o.y;
int a1=qurant(a);
int b1=qurant(b);
if (a1!=b1)
return a1<b1;
return cross(a,b)>0;
}
void qs(int h,int g,point &o)
{
int l=h,k=g;
point mid=dot[(l+k)/2];
while (l<=k)
{
while (cmp(dot[l],mid,o)) l++;
while (cmp(mid,dot[k],o)) k--;
if (l<=k)
{
swap(dot[l],dot[k]);
l++;
k--;
}
}
if (l<g) qs(l,g,o);
if (h<k) qs(h,k,o);
}
void gettwo(point a,point b,point &c,point &d)
{
static line u;
static point p[5],q[5];
static int sum=0,j=0,tot=0;
sum=tot=0;
setline(u,a,b);
for (j=1;j<=4;j++)
if (!para(u,l[j]))
p[++tot]=getcommon(u,l[j]);
p[0]=p[tot];
for (j=1;j<=tot;j++)
if ((!equal(p[j].x,p[j-1].x)) || (!equal(p[j].y,p[j-1].y)))
if (p[j].x<=1.0+eps && p[j].x>=-eps)
if (p[j].y<=1.0+eps && p[j].y>=-eps)
q[++sum]=p[j];
c=q[1];
d=q[2];
}
extended dis(point a,point b)
{
a.x-=b.x;
a.y-=b.y;
return sqrt(a.x*a.x+a.y*a.y);
}
extended dis(line u,point a)
{
return fabs(u.a*a.x+u.b*a.y+u.c)/sqrt(u.a*u.a+u.b*u.b);
}
void getleng(extended &leng,point &bot,point &o,int i)
{
static extended tmpi=0,tmpi_1=0;
tmpi=dis(spot[i],o);
tmpi_1=dis(spot[i+1],o);
if (tmpi>tmpi_1)
{
leng=tmpi;
bot=spot[i+1];
}
else
{
leng=tmpi_1;
bot=spot[i];
}
}
bool inter(point a,point b,point c,point d)
{
return max(a.x,b.x)>=min(c.x,d.x)
&& max(a.y,b.y)>=min(c.y,d.y)
&& max(c.x,d.x)>=min(a.x,b.x)
&& max(c.y,d.y)>=min(a.y,b.y)
&& cross(a,c,b)*cross(a,b,d)>=-eps
&& cross(c,a,d)*cross(c,d,b)>=-eps;
}
extended calc(point a,point o,extended &square)
{
static int i=0,sums=0,sta=0,tots=0,j=0;
static extended totarea=0,disx=0,disy=0,
heix,heiy,rangx,lengx,lengy,rangy,upx,downx,upy,downy,tempos;
static line u,v;
static point botx=ori,boty=ori,b=ori;
extended posibility=0;
memset(area,0,sizeof(area));
memset(spot,0,sizeof(spot));
memset(dot,0,sizeof(dot));
totarea=posibility=disx=disy=square=0;
heix=heiy=rangx=lengx=lengy=rangy=upx=downx=upy=downy=tempos=0;
sums=0,tots=0;
b=ori,botx=ori,boty=ori;
for (i=0;i<=3;i++)
{
sums+=2;
gettwo(matrix[i],o,dot[sums],dot[sums-1]);
}
sums+=2;
gettwo(a,o,dot[sums],dot[sums-1]);
b=dot[sums];
if (equal(b.x,a.x) && equal(b.y,a.y)) b=dot[sums-1];
qs(1,sums,o);
for (sta=1;sta<=sums;sta++)
if (equal(a.x,dot[sta].x) && equal(a.y,dot[sta].y))
break;
for (i=sta;i<=sums;i++) spot[++tots]=dot[i];
for (i=1;i<=sta-1;i++) spot[++tots]=dot[i];
spot[tots+1]=spot[1];
for (i=6;i<=tots;i++)
{
area[i]=trangle(spot[i],spot[i+1],o);
totarea+=area[i];
}
for (i=1;i<=5;i++)
{
area[i]=trangle(spot[i],spot[i+1],o);
totarea-=area[i+5];
posibility+=totarea*area[i]*2.0;
if (zero(area[i]) || zero(area[i+5])) continue;
setline(u,spot[i],spot[i+1]);
setline(v,spot[i+5],spot[i+6]);
if (para(u,v))
posibility+=(area[i]*area[i+5]);
else
{
heix=dis(u,o);
heiy=dis(v,o);
getleng(lengx,botx,o,i);
getleng(lengy,boty,o,i+5);
rangx=dis(spot[i],spot[i+1]);
rangy=dis(spot[i+5],spot[i+6]);
upx=sqrt(lengx*lengx-heix*heix);
upy=sqrt(lengy*lengy-heiy*heiy);
downx=upx-rangx;
downy=upy-rangy;
tempos=0.;
tempos+=
((heiy*heix*(log(upx/downx))-downy*rangx)*heix*heiy/4.0);
tempos+=
((heix*heiy*(log(upy/downy))-downx*rangy)*heiy*heix/4.0);
if (!inter(a,o,botx,boty))
tempos=area[i]*area[i+5]*2.0-tempos;
posibility+=tempos;
}
}
for (i=1;i<=10;i++)
if (equal(spot[i].x,b.x) && equal(spot[i].y,b.y)) break;
else
square+=area[i];
return posibility;
}
public:
void calcposforsegment()
{
int i=0;
point one=ori,two=ori;
extended square=0;
for (i=1;i<=4;i++)
setline(l[i],matrix[i-1],matrix[i%4]);
for (i=1;i<=segs;i++)
{
gettwo(seg[i].a,seg[i].b,one,two);
if (dis(one,seg[i].a)<dis(one,seg[i].b))
{
posis[i]=calc(one,seg[i].a,square)
+calc(two,seg[i].b,square);
}
else
{
posis[i]=calc(two,seg[i].a,square)
+calc(one,seg[i].b,square);
}
posis[i]=square*(1.0-square)*2.0-posis[i];
positot+=posis[i];
}
}
} class2;
class classthree
{
public:
void calcandprintfinal()
{
printf("%.17f",(double)(posia+positot/2.0));
}
} class3;
int main()
{
freopen("seal.in","r",stdin);
freopen("seal.out","w",stdout);
class1.initandgetsegment();
class2.calcposforsegment();
class3.calcandprintfinal();
return 0;
}
加强Code:
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
typedef long double extended;
const extended eps=1e-12;
#define maxn 100005
#define zero(x) (fabs(x)<eps)
#define equal(x,y) (zero(((x)-(y))))
struct point{extended x,y;};
const point ori={0,0};
const point matrix[4]={{0,0},{0,1},{1,1},{1,0}};
struct segment{point a,b;} seg[maxn];
struct line{extended a,b,c;};
extended posia=0,positot=0;
int segs=0;
int cmp(const void *p,const void *q)
{
point a=(*(point*)p),b=(*(point*)q);
if (equal(a.x,b.x))
if (equal(a.y,b.y)) return 0;
else if (a.y>b.y) return 1;
else return -1;
else if (a.x>b.x) return 1;
else return -1;
}
class classone
{
private:
int n,i;
extended h,w;
int top,hea;
point node[maxn],qup[maxn],qdn[maxn];
extended cross(point a,point b,point c,point d)
{
b.x-=a.x,b.y-=a.y;
d.x-=c.x,d.y-=c.y;
return b.x*d.y-d.x*b.y;
}
extended cross(point a,point b)
{
return a.x*b.y-b.x*a.y;
}
public:
void initandgetsegment()
{
double a=0,b=0;
scanf("%d%lf%lf",&n,&a,&b);
h=a;w=b;
for (i=1;i<=n;i++)
{
scanf("%lf%lf",&a,&b);
node[i].x=a;
node[i].y=b;
node[i].x/=h;
node[i].y/=w;
}
extended area1=0,area2=0;
qsort(node+1,n,sizeof(node[0]),cmp);
top=hea=2;
qup[1]=qdn[1]=node[1];
qup[2]=qdn[2]=node[2];
for (i=3;i<=n;i++)
{
while (cross(qup[top-1],qup[top],qup[top],node[i])>=-eps && top>1) top--;
while (cross(qdn[hea-1],qdn[hea],qdn[hea],node[i])<=eps && hea>1) hea--;
qup[++top]=node[i];
qdn[++hea]=node[i];
}
for (i=2;i<=top;i++)
{
area1+=cross(qup[i-1],qup[i]);
seg[++segs].a=qup[i-1];
seg[segs].b=qup[i];
}
area1+=cross(qup[top],qup[1]);
area1=fabs(area1);
for (i=2;i<=hea;i++)
{
area2+=cross(qdn[i-1],qdn[i]);
seg[++segs].a=qdn[i-1];
seg[segs].b=qdn[i];
}
area2+=cross(qdn[hea],qdn[1]);
area2=fabs(area2);
posia=(area1+area2)/2.0;
}
} class1;
class classtwo
{
private:
point dot[15],spot[15];
extended posis[maxn],area[15];
line l[5];
extended max(extended a,extended b)
{
if (a>b) return a;
return b;
}
extended min(extended a,extended b)
{
if (a<b) return a;
return b;
}
void swap(point &a,point &b)
{
static point tmp;
tmp=a;a=b;b=tmp;
}
void swap(line &a,line &b)
{
static line tmp;
tmp=a;a=b;b=tmp;
}
extended cross(point a,point b)
{
return a.x*b.y-b.x*a.y;
}
extended cross(point o,point a,point b)
{
a.x-=o.x,b.x-=o.x;
a.y-=o.y,b.y-=o.y;
return a.x*b.y-b.x*a.y;
}
extended trangle(point a,point b,point c)
{
return fabs(cross(a,b)+cross(b,c)+cross(c,a))/2.0;
}
void setline(line &u,point a,point b)
{
u=(line){0.0,0.0,0.0};
u.a=a.y-b.y;
u.b=b.x-a.x;
u.c=cross(a,b);
if (zero(u.a))
{
u.a=0.0;
u.c/=u.b;
u.b=1.0;
}
else
{
u.b/=u.a;
u.c/=u.a;
u.a=1.0;
}
if (u.a<0) u.a=-u.a,u.b=-u.b+0.0,u.c=-u.c+0.0;
}
bool para(line &u,line &v)
{
return (equal(u.a,v.a) && equal(u.b,v.b));
}
point getcommon(line u,line v)
{
if (zero(v.b)) swap(u,v);
point o;
o=ori;
if (zero(u.b))
{
o.x=-u.c/u.a;
o.y=-v.a/v.b*o.x-v.c/v.b;
}
else
{
static extended k1,k2,b1,b2;
k1=-u.a/u.b;
b1=-u.c/u.b;
k2=-v.a/v.b;
b2=-v.c/v.b;
o.x=(b1-b2)/(k2-k1);
o.y=k1*o.x+b1;
}
return o;
}
int qurant(point a)
{
if (a.x>0 && a.y>=0) return 1;
if (a.x<=0 && a.y>0) return 2;
if (a.x<0 && a.y<=0) return 3;
return 4;
}
bool cmp(point a,point b,point &o)
{
a.x-=o.x,a.y-=o.y;
b.x-=o.x,b.y-=o.y;
int a1=qurant(a);
int b1=qurant(b);
if (a1!=b1)
return a1<b1;
return cross(a,b)>0;
}
void qs(int h,int g,point &o)
{
int l=h,k=g;
point mid=dot[(l+k)/2];
while (l<=k)
{
while (cmp(dot[l],mid,o)) l++;
while (cmp(mid,dot[k],o)) k--;
if (l<=k)
{
swap(dot[l],dot[k]);
l++;
k--;
}
}
if (l<g) qs(l,g,o);
if (h<k) qs(h,k,o);
}
void gettwo(point a,point b,point &c,point &d)
{
static line u;
static point p[5],q[5];
static int sum=0,j=0,tot=0;
sum=tot=0;
setline(u,a,b);
for (j=1;j<=4;j++)
if (!para(u,l[j]))
p[++tot]=getcommon(u,l[j]);
p[0]=p[tot];
for (j=1;j<=tot;j++)
if ((!equal(p[j].x,p[j-1].x)) || (!equal(p[j].y,p[j-1].y)))
if (p[j].x<=1.0+eps && p[j].x>=-eps)
if (p[j].y<=1.0+eps && p[j].y>=-eps)
q[++sum]=p[j];
c=q[1];
d=q[2];
}
extended dis(point a,point b)
{
a.x-=b.x;
a.y-=b.y;
return sqrt(a.x*a.x+a.y*a.y);
}
extended dis(line u,point a)
{
return fabs(u.a*a.x+u.b*a.y+u.c)/sqrt(u.a*u.a+u.b*u.b);
}
void getleng(extended &leng,point &bot,point &o,int i)
{
static extended tmpi=0,tmpi_1=0;
tmpi=dis(spot[i],o);
tmpi_1=dis(spot[i+1],o);
if (tmpi>tmpi_1)
{
leng=tmpi;
bot=spot[i+1];
}
else
{
leng=tmpi_1;
bot=spot[i];
}
}
bool inter(point a,point b,point c,point d)
{
return max(a.x,b.x)>=min(c.x,d.x)
&& max(a.y,b.y)>=min(c.y,d.y)
&& max(c.x,d.x)>=min(a.x,b.x)
&& max(c.y,d.y)>=min(a.y,b.y)
&& cross(a,c,b)*cross(a,b,d)>=-eps
&& cross(c,a,d)*cross(c,d,b)>=-eps;
}
extended calc(point a,point o,extended &square)
{
static int i=0,sums=0,sta=0,tots=0,j=0;
static extended totarea=0,disx=0,disy=0,
heix,heiy,rangx,lengx,lengy,rangy,upx,downx,upy,downy,tempos;
static line u,v;
static point botx=ori,boty=ori;
extended posibility=0;
memset(area,0,sizeof(area));
memset(spot,0,sizeof(spot));
memset(dot,0,sizeof(dot));
totarea=posibility=disx=disy=square=0;
heix=heiy=rangx=lengx=lengy=rangy=upx=downx=upy=downy=tempos=0;
sums=0,tots=0;
botx=ori,boty=ori;
for (i=0;i<=3;i++)
{
sums+=2;
gettwo(matrix[i],o,dot[sums],dot[sums-1]);
}
sums+=2;
gettwo(a,o,dot[sums],dot[sums-1]);
qs(1,sums,o);
for (sta=1;sta<=sums;sta++)
if (equal(a.x,dot[sta].x) && equal(a.y,dot[sta].y))
break;
for (i=sta;i<=sums;i++) spot[++tots]=dot[i];
for (i=1;i<=sta-1;i++) spot[++tots]=dot[i];
spot[tots+1]=spot[1];
for (i=6;i<=tots;i++)
{
area[i]=trangle(spot[i],spot[i+1],o);
totarea+=area[i];
}
for (i=1;i<=5;i++)
{
area[i]=trangle(spot[i],spot[i+1],o);
square+=area[i];
totarea-=area[i+5];
posibility+=totarea*area[i]*2.0;
if (zero(area[i]) || zero(area[i+5])) continue;
setline(u,spot[i],spot[i+1]);
setline(v,spot[i+5],spot[i+6]);
if (para(u,v))
posibility+=(area[i]*area[i+5]);
else
{
heix=dis(u,o);
heiy=dis(v,o);
getleng(lengx,botx,o,i);
getleng(lengy,boty,o,i+5);
rangx=dis(spot[i],spot[i+1]);
rangy=dis(spot[i+5],spot[i+6]);
upx=sqrt(lengx*lengx-heix*heix);
upy=sqrt(lengy*lengy-heiy*heiy);
downx=upx-rangx;
downy=upy-rangy;
tempos=0.;
tempos+=
((heiy*heix*(log(upx/downx))-downy*rangx)*heix*heiy/4.0);
tempos+=
((heix*heiy*(log(upy/downy))-downx*rangy)*heiy*heix/4.0);
if (!inter(a,o,botx,boty))
tempos=area[i]*area[i+5]*2.0-tempos;
posibility+=tempos;
}
}
return posibility;
}
public:
void calcposforsegment()
{
int i=0;
point one=ori,two=ori;
extended square=0;
for (i=1;i<=4;i++)
setline(l[i],matrix[i-1],matrix[i%4]);
for (i=1;i<=segs;i++)
{
gettwo(seg[i].a,seg[i].b,one,two);
if (dis(one,seg[i].a)<dis(one,seg[i].b))
{
posis[i]=calc(one,seg[i].a,square)
+calc(two,seg[i].b,square);
}
else
{
posis[i]=calc(two,seg[i].a,square)
+calc(one,seg[i].b,square);
}
posis[i]=square*(1.0-square)*2.0-posis[i];
positot+=posis[i];
}
}
} class2;
class classthree
{
public:
void calcandprintfinal()
{
printf("%.17f",(double)(posia+positot/2.0));
}
} class3;
int main()
{
freopen("seal.in","r",stdin);
freopen("seal.out","w",stdout);
class1.initandgetsegment();
class2.calcposforsegment();
class3.calcandprintfinal();
return 0;
}