1023 The Best Polygon (35)(35 分)
An n-gon is a polygon with n sides. For example, a triangle is a 3-gon. Now you are asked to find the best n-gon in a given convex N-gon. The vertices of the n-gon are selected from vertices of the N-gon. The n-gon you are supposed to find must have the largest area among all possible n-gons, which means that it approximates the N-gon the best. The figure below shows the best 6-gon (the shaded part) in a 10-gon.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N ( 6 <= N <= 300 ) which is the total number of vertices of the convex N-gon, and n ( 6 <= n <= min(10, N) ) which is the total number of vertices of the approximating convex n-gon. Then N lines follow, the i-th line gives the 2-D coordinates (x, y) of the i-th vertex ( i = 0, … , N-1 ). The x and y coordinates in a line are real numbers with their absolute values no more than 1000, and they are separated by a space.
Output Specification:
Print in a line all the vertex indices of the best n-gon in descending order. All the numbers are separated by a space and there must be no extra space at the beginning or the end of the line. It is guaranteed that the solution is unique.
Sample Input:
10 6
133.0 1.0
544.0 71.0
558.0 206.0
536.0 338.0
463.0 436.0
330.0 503.0
188.0 499.0
305.0 2.0
55.0 410.0
2.0 140.0
Sample Output:
9 8 5 3 1 0
ADS project 4。
讲道理这么难的题目给我们当project,老师未免也太瞧得起我们了。
虽然写完了提交上去能AC。
但是我对我写出来的东西也不太能清楚的理解,都是凭感觉写的。。。
先贴下代码吧。。。
#include <bits/stdc++.h>
using namespace std;
int n, m;/*the number of the nodes, the number of sides of the Polygonal we want, respectively*/
double dp[305][15];/*we use dp[i][j] represent start with a certain point, The maximum area of the j polygon in the previous i points*/
int f[305][15];/*we use f[i][j] represent when we calculate dp[i][j], we remember the last node we pick*/
int pre[305][15];/*we use pre[i][j] to remember the road*/
struct point{
int index;
double x, y;
point(double a, double b):x(a), y(b){}
point(){}
double det (const point& p) const/*Calculate cross product*/
{
return x*p.y - y*p.x;
}
point operator- (const point& p) /*Operators "-" Overloaded*/
{
return point(x - p.x, y - p.y);
}
bool operator< (const point& p) const/* we use graham algorithm to sort the node, so we need sort nodes with x and y first*/
{
if (x != p.x) return x < p.x;
else return y < p.y;
}
}arr[305], tmp[305];
vector<int> res, temp;/*remember the result*/
double calarea(const point& a, const point& b, const point& c)/*Calculate the area of the triangle*/
{
double q, w, e, p, s;
q = sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
w = sqrt((a.x-c.x)*(a.x-c.x)+(a.y-c.y)*(a.y-c.y));
e = sqrt((b.x-c.x)*(b.x-c.x)+(b.y-c.y)*(b.y-c.y));
p = (q + w + e) / 2;
return sqrt(p*(p-q)*(p-w)*(p-e));/*Helen's formula*/
}
double caldis(const point& a, const point& b)/*Calculate the distance between two points*/
{
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
void move(void)/*Because the ring cannot be dynamically planned, we need to enumerate the starting points at a time*/
{ /* and turn DP on the ring into a DP on the chain.*/
arr[n+1] = arr[1];
for (int i = 1; i <= n; i++)
{
arr[i] = arr[i+1];
}
}
void graham(void)/*graham algorithm to make the vertex sorted*/
{
sort(tmp, tmp+n);
int k = 0, i; /*k represents the number of convex vertices*/
/*Constructs the underside of the convex hull*/
for(i=0; i<n; i++)
{
while(k>1 && (arr[k-1]-arr[k-2]).det(tmp[i]-arr[k-1])<0) k--;
arr[k++] = tmp[i];
}
/*Upper side of structured bulge*/
int t = k;
for(i=n-2; i>=0; i--)
{
while(k>t && (arr[k-1]-arr[k-2]).det(tmp[i]-arr[k-1])<0) k--;
arr[k++] = tmp[i];
}
for (i = k; i >= 1; i--)/*in order to easy to dp, we add every index 1*/
{
arr[i] = arr[i-1];
}
n = k;/*delete the point on the convex hull*/
}
int main(void)
{
scanf("%d%d", &n, &m);
int start, i, j, k;
for (i = 0; i < n; i++)/*input*/
{
scanf("%lf%lf", &tmp[i].x, &tmp[i].y);
tmp[i].index = i;/*set the index*/
}
graham();
double ans = -1, ma = -1;/*"ans" represent the max area of the m Polygonal*/
int index1;
for (start = 0; start < n; start++)/*Enumerate n starting points*/
{
memset(f, 0, sizeof(f));
memset(dp, 0, sizeof(dp));
memset(pre, 0, sizeof(pre));/*initialization*/
for (i = 2; i <= n; i++)/*we make dp[i][2] is the distance of the start node and the i-node*/
{
if (caldis(arr[i], arr[1]) > dp[i-1][2])/*choose the best two node*/
{
dp[i][2] = caldis(arr[i], arr[1]);/*update the dp[i][2]*/
f[i][2] = i;/*remember the last node*/
}
else
{
dp[i][2] = dp[i-1][2];/*update the dp[i][2]*/
f[i][2] = f[i-1][2];/*remember the last node*/
}
}
for (i = 1; i <= n; i++) dp[i][2] = 0;/*because two nodes have 0 area, so dp[i][2] is 0*/
for (j = 3; j <= m; j++)/*dp[i][j] = max(dp[i-1][j], dp[x][j-1] + New triangle (1 <= x <= i-1)) */
{
for (i = j; i <= n; i++)
{
ma = - 1;
for (k = j-1; k < i; k++)
{
int temp = f[k][j-1];
double t = calarea(arr[temp], arr[1], arr[i]);/*calculate the area of the new triangle*/
if (t + dp[k][j-1] > ma)
{
ma = t + dp[k][j-1];/*update the max*/
index1 = i;
pre[i][j] = k;/*remember the road*/
}
}
if (ma >= dp[i-1][j])/*dp[i][j] = max(dp[i-1][j], dp[x][j-1] + New triangle (1 <= x <= i-1)) */
{
f[i][j] = index1;/*update the dp[i][j] and the f[i][j]*/
dp[i][j] = ma;/*update the dp[i][j] and the f[i][j]*/
}
else
{
f[i][j] = f[i-1][j];/*update the dp[i][j] and the f[i][j]*/
dp[i][j] = dp[i-1][j];/*update the dp[i][j] and the f[i][j]*/
}
}
}
if (dp[n][m] > ans)/*compare the The maximum value of this time*/
{
temp.clear();
ans = dp[n][m];/*update the answer*/
int now = f[n][m];
j = m;
while (j >= 2)
{
temp.push_back(arr[now].index);/*find the road*/
now = pre[now][j];/*find the road*/
j--;
}
temp.push_back(arr[1].index);/*find the road*/
res = temp;/*update the result road*/
}
move();/*update the start node*/
}
sort(res.begin(), res.end());
for (i = res.size() - 1; i > 0; i--)/*output*/
{
printf("%d ", res[i]);
}
printf("%d", res[i]);
}
总体思路就是DP
然后是先用graham算法算了一下凸包。然后我发现貌似题目后台给的数据给的不是凸包诶。因为如果我没有那句graham算法里的n = k,就会有测试点TLE和WA,如果是我哪里写错了,请在评论区告诉一下我哈!
graham求了凸包并且放到arr数组里面后就开始dp
我是这么DP的:
枚举环上的起点,以某个点为起点时
dp[i][j]表示以此点为起点时,前i个点选取j个点所能达到的最大面积
f[i][j]表示我们算出dp[i][j]时,最后选用的那个点是什么
比如从下表为1的点开始,dp[5][3]是从1,2,3,4,5五个点中
选取3个点组成的面积最大,假设是2,4,5三个点的面积最大
那么f[5][3]就等于5
pre[i][j]来记录选点的路径,比如pre[5][3]意思就是当我们算前五个点里哪三个点组成的面积是最大的时候,pre[5][3] = 4,就是最后选的点的前一个点我们记下来,最后就可以统计一遍输出了。
然后我的dp方程是:
dp[i][j] = max(dp[i][j], dp[x][j-1](j-1<=x<i)
+ 起点,f[x][j-1], i 这三个点组成的新三角形面积)
不会证,猜的一个dp方程
我寻思着,你说前10个点里最大的四边形,是不是肯定是由前3,4…9个点里最大的三角形+一个新三角形组成的呢,感觉貌似没毛病呀hhhh
然后每次dp完move()一下,换一下起点继续DP
时间复杂度O(N^3*n)
写归写,反正到时候考顶级的时候我肯定dfs暴力搜索啊。。
这种DP反正我写完还是晕晕乎乎的。
如果有更简单的做法请赐教哦!