区间可以划分为左右两边,而且左右两边的答案互不影响,可以进行区间dp。常用方法:迭代式、记忆化搜索
环形区间dp
环形石子dp
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 410;
const int inf = 0x3f3f3f3f;
int n;
int s[N], w[N];
int f[N][N], g[N][N];
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++ )
{
cin >> w[i];
w[i + n] = w[i];
}
memset(f, 0x3f, sizeof f);
memset(g, -0x3f, sizeof g);
for(int i = 1; i <= n * 2; i ++ ) s[i] = s[i - 1] + w[i];
for(int len = 1; len <= n; len ++ )
for(int l = 1; l + len - 1 <= n * 2; l ++ )
{
int r = l + len - 1;
if(len == 1) f[l][r] = g[l][r] = 0;
else
{
for(int k = l; k < r; k ++ )
{
f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r] + s[r] - s[l - 1]);
g[l][r] = max(g[l][r], g[l][k] + g[k + 1][r] + s[r] - s[l - 1]);
}
}
}
int ans1 = inf, ans2 = -inf;
for(int i = 1; i <= n; i ++ )
{
ans1 = min(ans1, f[i][i + n - 1]);
ans2 = max(ans2, g[i][i + n - 1]);
}
cout << ans1 << endl << ans2 << endl;
}
能量项链
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 210;
int f[N][N];
int w[N];
int n;
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++ )
{
cin >> w[i];
w[i + n] = w[i];
}
for(int len = 3; len <= n + 1; len ++ )
for(int l = 1; l + len - 1 <= 2 * n; l ++ )
{
int r = l + len - 1;
for(int k = l + 1; k < r; k ++ )
{
f[l][r] = max(f[l][r], f[l][k] + f[k][r] + w[l] * w[k] * w[r]);
}
}
int ans = 0;
for(int i = 1; i <= n; i ++ ) ans = max(ans, f[i][i + n]);
cout << ans;
}
区间dp记录方案数
加分二叉树
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 33;
int g[N][N];
int n;
int w[N];
int f[N][N];
void dfs(int l, int r)
{
if(l > r) return;
int root = g[l][r];
cout << root << " ";
dfs(l, root - 1);
dfs(root + 1, r);
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> w[i];
for(int len = 1; len <= n; len ++ )
for(int l = 1; l + len - 1 <= n; l ++ )
{
int r = l + len - 1;
if(len == 1)
{
f[l][r] = w[l];
g[l][r] = l;
continue;
}
for(int k = l; k <= r; k ++ )
{
int left = k == l ? 1 : f[l][k - 1];
int right = k == r ? 1 : f[k + 1][r];
int get = left * right + w[k];
if(f[l][r] < get)
{
f[l][r] = get;
g[l][r] = k;
}
}
}
cout << f[1][n] << endl;
dfs(1, n);
}
区间dp和高精度
凸多边形划分
#include<bits/stdc++.h>
using namespace std;
const int N = 55;
inline __int128 read(){
__int128 x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if(ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline void print(__int128 x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
__int128 f[N][N];
__int128 w[N];
const __int128 inf = 1e27;
int main(){
int n;
cin >>n;
for(int i =1 ; i <= n ; i++) w[i] = read();
for(int len = 3; len <= n; len++){
for(int l = 1; l +len - 1 <= n; l++){
int r = l + len -1;
f[l][r] = inf;
for(int k = l+ 1; k < r; k++){
f[l][r] = min(f[l][r], f[l][k] + f[k][r] + w[l]*w[k]*w[r]);
}
}
}
print(f[1][n]);
return 0;
}