對於動態規劃的理解
從大二起,也做了不少的動態規劃題,但對於很多動態規劃狀態還是一知半解,究其原因,是在平時做題的過程中,不求甚解,遇到問題只是匆匆看看題解,而不深入探討。導致很多問題都模模糊糊的過去了,做題也等於沒有做。從現在開始正式的反思總結。新的一年,新的開始^_^
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 <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
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;
}