1023 The Best Polygon (35)(35 分)

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反正我写完还是晕晕乎乎的。
如果有更简单的做法请赐教哦!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值