North American Invitational Programming Contest (NAIPC) 2019 Piece of Cake

Piece of Cake

  • 题目
    • 题意
    • 题解

题目

Alice received a cake for her birthday! Her cake can be described by a convex polygon with n vertices. No three vertices are collinear.

Alice will now choose exactly k random vertices (k≥3) from her cake and cut a piece, the shape of which is the convex polygon defined by those vertices. Compute the expected area of this piece of cake.

Input
Each test case will begin with a line with two space-separated integers n and k (3≤k≤n≤2500), where n is the number of vertices of the cake, and k is the number of vertices of the piece that Alice cuts.

Each of the next n lines will contain two space-separated real numbers x and y (−1e9≤x,y≤1e9), where (x,y) is a vertex of the cake. The vertices will be listed in clockwise order. No three vertices will be collinear. All real numbers have at most 6 digits after the decimal point.

Output
Output a single real number, which is the expected area of the piece of cake that Alice cuts out. Your answer will be accepted if it is within an absolute error of 1e−6.

题意

给定n个点的凸包,求随机选其中k个点作为多边形顶点的面积期望。注意保证1e-6的精度。

题解

首先求凸包面积,即顺时针或逆时针求相邻两点之间的叉积之和的绝对值。其实根据正负也可判断点集是顺时针还是逆时针。
至于为什么,其实也很好理解,两点之间的叉积,在几何上表示由这两个向量组成的平行四边形面积。除以二即为原点与两点之间组成三角形的面积。
那么在一个多边形的顺时针方向连续计算相邻两点的叉积。
North American Invitational Programming Contest (NAIPC) 2019 Piece of Cake_第1张图片
很显然
O A → ∗ O B → + O B → ∗ O C → + O C → ∗ O D → + O D → ∗ O E → + O E → ∗ O A → 2 = S \frac{\overrightarrow{OA}*\overrightarrow{OB}+\overrightarrow{OB}*\overrightarrow{OC}+\overrightarrow{OC}*\overrightarrow{OD}+\overrightarrow{OD}*\overrightarrow{OE}+\overrightarrow{OE}*\overrightarrow{OA}}{2}=S 2OA OB +OB OC +OC OD +OD OE +OE OA =S
几个三角形面积相加等于这个多边形面积,注意 O E → ∗ O A → \overrightarrow{OE}*\overrightarrow{OA} OE OA 是个负数,相当于把三角形OAE删掉了。

计算其中k个点组成的多边形面积期望,很显然不能暴力枚举求和,那会是 C n k C_{n}^{k} Cnk的数量,联系刚才求多边形面积的时候,很显然是把三角形分割成诸多三角形再求和而成,那能不能将这 C n k C_{n}^{k} Cnk个多边形分成三角形,再计算其贡献度。

首先任意枚举两个点,还是以这张图为例,枚举AB,我想知道有多少符合条件的多边形包含AB两点,因为包含AB即意味着该多边形包含三角形OAB。很显然是 C n − 2 k − 2 C_{n-2}^{k-2} Cn2k2个,因为固定AB后,要在剩余的点集中再选k-2个。

但是计算的过程中要避免出现重叠,所以枚举多边形在凸包上顺时针的边界,例如k=3时,顺时针枚举A,D,剩余的k-2个点要在顺时针方向A至D的范围内枚举,即只能在点集{B,C}中枚举。这样很显然枚举A时,第二个点要从A顺时针方向的第k-1个点开始枚举(即从C开始)。保证范围内有k-2个点。

最后统一除以 C n k C_{n}^{k} Cnk,注意精度影响。

代码:

#include
using namespace std;
const int eps=1e-5;
struct Point
{
    long double x, y;
    double angle, dis;
    Point() {}
    Point(double x0, double y0): x(x0), y(y0) {}
};
typedef vector Points;
Points points;
long double cross(Point x,Point y)
{
    return x.x*y.y-x.y*y.x;
}
const int N=2600;
long double C[N][N];
long double getc(int i,int j)
{
    if(ieps)return C[i][j];
    return (C[i][j]=(getc(i-1,j)+getc(i-1,j-1)));
}

int main()
{
    int n,k;
    cin>>n>>k;
    long double x,y;
    for(int i=0; i>x>>y;
        points.push_back(Point(x,y));
    }
    long double ans=0;
    for(int i=0; i

你可能感兴趣的:(题目)