关于动态规划的理解

对于动态规划的理解

从大二起,也做了不少的动态规划题,但对于很多动态规划状态还是一知半解,究其原因,是在平时做题的过程中,不求甚解,遇到问题只是匆匆看看题解,而不深入探讨。导致很多问题都模模糊糊的过去了,做题也等于没有做。从现在开始正式的反思总结。新的一年,新的开始^_^

 1. ZOJ 1679  Telescope

  题意:这道题是给出一个圆,上面有n个点,从中选出m个点,选择一种方案使得构成的m多边形面积最大(m个点依次顺序连接形成多边形)。

题解:(动态规划很多时候都需要枚举子问题的状态,从而推出所需问题的最优策略,这样,对于子问题的枚举策略就显得至关重要。既然是枚举,所有的情况都不能遗漏,枚举条件的选取恰当与否决定了问题能否顺利解决)这题的数据规模是40,因为涉及到最大面积,考虑动态规划,根据题意,猜测是区间DP,对于DP参数的设定:

dp(i, j, k) 表示以i开始,以j结束的拥有k个点的多边形的最大面积,这昂最总答案是max{dp(i, j, m)}.

状态转移方程:dp(i, j, k) = max{ dp(i, j, k) , dp(i, q, k - 1) + Triangle(i, q, j) }.

代码:

#include 
#include 
#include 
#include 
#include 

using namespace std;
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
#define N 50


int n, m;
double dp[N][N][N], _area[N][N][N];
struct Point{
	double x, y;
}P[N];

double cross(Point a, Point b, Point c)  
{  
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);  
}  

double area(Point a, Point b, Point c)  
{  
    return fabs(cross(a, b, c)/2.0);  
} 

void init(){
	for(int i = 0; i < n; i++)
		for(int j = 0; j < n; j++)
			for(int k = 0; k < n; k++){
					_area[i][j][k] = area(P[i], P[j], P[k]);
				}
	memset(dp, 0, sizeof dp);
}

void DP(){
	for(int i = 0; i < n; i++)
		for(int j = i + 2; j < n; j++)
			for(int k = 3; k <= m; k++)
				for(int q = i + k - 2 ; q < j; q++)
					dp[i][j][k] = max(dp[i][j][k], dp[i][q][k-1] + _area[i][j][q]);

	double ans = -INF;
	for(int i = 0; i < n; i++)
		for(int j = i + m - 1; j < n; j++){
			ans = max(ans, dp[i][j][m]);
		}
	printf("%.6lf\n", ans);
}

int main(){
	// freopen("2016.txt", "r", stdin);
	while(scanf("%d%d", &n, &m) && n + m){
		for(int i = 0; i < n; i++){
			double tmp;
			scanf("%lf", &tmp);
			tmp = 2 * PI * tmp;
			P[i].x = cos(tmp);
			P[i].y = sin(tmp);
		}
		init();
		DP();
	}
	return 0;
}




你可能感兴趣的:(DP,动态规划成长系列)