这里简述一下区间DP:
主要思想:
区间动态规划问题一般都是考虑对于每段区间,他们的最优值都是由几段更小区间的最优值得到,是分治思想的一种应用,将一个区间问题不断划分为更小的区间直至一个素组成的区间,枚举他们的组合,求合并后的最优值。
定义状态:设dp[i][j]为区间i,j之间的最小代价(实际看题意)
实现过程:
for(int p = 1 ; p <= n ; p++) { //p是区间的长度,作为阶段
for(int i = 1 ; i <= n ; i++) { //i是穷举区间的起点
int j = i+p-1; //j为区间的终点
for(int k = i ; k < j ; k++) //状态转移
dp[i][j] = min{dp[i][k]+dp[k+1][j]+w[i][j]};//这个是看题目意思,有的是要从k开始不是k+1
dp[i][j]= max{dp[i][k]+dp[k+1][j]+w[i][j]};
}
}
对于这一题来说:首先得明确状态转移方程为dp[i][j]=min(dp[i][k],dp[k][j])+num[j]-num[i] (i<k<j),且这里k不能等于i和j,因为k代表的是区间i,j之间可以切割的点,显然要切割中间的,不需要切割边上的,所以这里要往外层加一层边界,即区间的最外边,因此有这题答案dp[0][n+1] 代表从最左边到最右边(0最左边n+1最右边)切割木条可以获得的最小值。
AC代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #define INF 0x3fffffff using namespace std; const int maxn = 60; int dp[maxn][maxn]; //dp[i][j]代表在区间i,j之间的最小代价 int num[maxn]; int main() { int L, n; while(scanf("%d", &L) && L) { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &num[i]); num[0] = 0; num[n + 1] = L; memset(dp, 0, sizeof(dp)); for(int p = 1; p <= n + 1; p++) for(int i = 0; i <= n + 1; i++) { int j = i + p; int MIN = INF; if(j > n + 1) break; for(int k = i + 1; k < j; k++) { int tmp = dp[i][k] + dp[k][j] + num[j] - num[i]; MIN = min(MIN, tmp); } if(MIN != INF) dp[i][j] = MIN; } printf("The minimum cutting is %d.\n", dp[0][n + 1]); } return 0; }