区间DP虽然入门十分简单,但是也需要记住一些步骤
方程形式上一般是f(l,r)=max(f(l,k)+f(k+1,r))+d(l,r)f(l,r)=max(f(l,k)+f(k+1,r))+d(l,r) (k属于l到r-1)
转移有这几步
枚举区间长度
枚举左端点,结合区间长度确认右端点
枚举区间分割点,转移
还会经常遇到环形区间DP,解决方法是破环成链,复制一倍数据,加到原有数据后面
然后转移只需要把枚举左端点的上限,由l+length≤nl+length≤n变为l+length≤2nl+length≤2n
枚举区间长度的上限不要变,仍然是n
最后遍历一遍从第i个数(i ≤≤ n)开始的长度为n的区间,取最大或最小值
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 1000 + 10;
int n,a[MAXN],f[MAXN][MAXN],g[MAXN][MAXN],s[MAXN];
int main() {
cin >> n;
memset(f,0x3f,sizeof(f));
for(int i=1; i<=2*n; i++) {
if(i<=n)
cin >> a[i];
if(i>n) a[i] = a[i-n];
f[i][i] = 0;
g[i][i] = 0;
s[i] = s[i-1] + a[i];
}
for(int i=2; i<=n; i++) {
for(int l=1; l+i-1<=2*n; l++) {
int r = l+i-1;
for(int k=l; k<r; k++) {
f[l][r] = min(f[l][r], f[l][k] + f[k+1][r]);
g[l][r] = max(g[l][r], g[l][k] + g[k+1][r]);
}
f[l][r] += s[r] - s[l-1];
g[l][r] += s[r] - s[l-1];
}
}
int minn = 1<<30;
int maxx = 0;
for(int i=1; i<=n; i++) {
minn = min(minn, f[i][i+n-1]);
maxx = max(maxx, g[i][i+n-1]);
}
printf("%d\n%d", minn, maxx);
return 0;
}

本文详细介绍了区间动态规划的基本概念和步骤,包括如何通过枚举区间长度、左端点和分割点来实现状态转移,并针对环形区间问题提供了解决方案。
3329

被折叠的 条评论
为什么被折叠?



