描述
给定一个凸多边形的N个顶点。你需要在凸多边形内找到M个点,使得这M个点也围成一个凸多边形,并且围成的面积尽可能大。
输入
第一行包含两个整数N和M,意义如前文所述。
接下来N行,每行两个整数Ai和Bi,表示按照逆时针顺序排列的凸多边形顶点坐标。
对于30%的数据,满足N<=5
对于100%的数据,满足N<=100
对于100%的数据,满足3<=M<N, |Ai|,|Bi|<=10000
输出
输出新凸多边形最大的面积,保留两位小数。
样例输入
4 3
0 0
1 0
1 1
0 1
样例输出
0.50
官方分析
本题可以用动态规划解决。
如上图所示,我们把凸多边形的N个顶点按顺序编号0~N-1。
f[i][j][k]表示起点是i,最后一个点是j的k边形,面积最大是多少。
转移方程:
f[i][j][k] = max{f[i][l][k-1] + S(i, l, j) | i < l < j}
其中S(i, l, j)是三角形ilj的面积。l是我们枚举的第k-1个点。
复杂度O(N^4)。
另外这道题还有一种”随机乱搞”的做法。
1) 首先随机选择M个点,计算当前M边形的面积。
2) 然后枚举一对点A和B,其中A是选中的点,B不是选中的点。
3) 如果改成选B不选A,能使多边形面积变大,就改选并重新计算面积。
4) 重复枚举一对点的过程,直到无法通过改选使面积增大。
5) 重复若干次随机选择初始M个点的过程。取其中最大能达到的面积。
AC
因为要枚举起点和终点,是枚举,所以所有情况都会考虑到,不去考虑中间的细节。只需要明白状态转移,加一条边是否是面积最大的,和前多边形最大的有关。
这里需要考虑到三角形公式:
海伦公式(知道三条边的长度)
在三角形ABC中,S=1/2 (向量AC x 向量AB) = 1/2 |AC| |AB| sinA
对于两个数的向量积(叉积):
(x1, y1) x (x2, y2) = x1y2 - x2y1
经过上面的计算,就可以得到程序中的面积公式了。
1 | #include <bits/stdc++.h> |