背包dp就是选与不选的情况
dp[j] = max(dp[j], dp[j - a[i][k] * 2 - 1] + k*i);//这是一个背包dp题的转移方程
背包问题的题目都有明显的选与不选的情况,大多都能抽象成上面的方程;
区间dp,从小区间推大区间枚举长度从小到大,反之则相反;
1 int main() { 2 int n; 3 cin >> n; 4 for (int i = 1; i <= n; ++i) { 5 for (int j = i + 1; j <= n; ++j) { 6 for (int k = i; k < j; ++k) 7 f[i][j] = max(f[i][j], f[i][k] + f[k + 1][j]); 8 } 9 }//不要从左到右去枚举区间,应该枚举区间长度 10 return 0; 11 }
正确写法
int main() { int n; cin >> n; for (int i = 1; i <n; ++i) {//i表示区间长度 for (int j = 1; j +i<= n; ++j) {//j表示左端点 for (int k = i; k < j+i; ++k)//k表示分割线 f[j][j+i] = max(f[j][j+i], f[j][k] + f[k + 1][j+i]); } } return 0; }
对于环的区间问题,把n变成2n在跑就行了
1 int main() { 2 int n; 3 cin >> n; 4 for (int i = 1; i <= n; ++i) { 5 cin >> a[i]; 6 a[i + n] = a[i]; 7 } 8 n *= 2; 9 for (int i = 1; i <n; ++i) { 10 for (int j = 1; j +i<= n; ++j) { 11 for (int k = i; k < j+i; ++k) 12 f[j][j+i] = max(f[j][j+i], f[j][k] + f[k + 1][j+i]); 13 } 14 } 15 int ans = 0;
16 n/=2; 16 for (int i = 1; i <= n; ++i) { 17 ans = max(ans, f[i][i + n - 1]);//右区间要减一 18 } 19 return 0; 20 }
难点是分割线的dp方程推导