acwing提高课区间dp
环形石子合并(环形)

样例输入:
4
4 5 9 4
样例输出:
43
54
代码模板:
//迭代式
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 410, INF = 0x3f3f3f3f;
int n;
int w[N], s[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];
}
for (int i = 1; i <= n * 2; i ++ ) s[i] = s[i - 1] + w[i];
memset(f, 0x3f, sizeof f);
memset(g, -0x3f, sizeof g);
for (int len = 1; len <= n; len ++ ) //长度
for (int l = 1; l + len - 1 <= n * 2; l ++ ) //左端点
{
int r = l + len - 1;
if (l == r) 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 minv = INF, maxv = -INF;
for (int i = 1; i <= n; i ++ )
{
minv = min(minv, f[i][i + n - 1]);
maxv = max(maxv, g[i][i + n - 1]);
}
cout << minv << endl << maxv << endl;
return 0;
}
能量项链(环形DP)

样例输入:
4
2 3 5 10
样例输出:
710
代码模板:
#include<cstdio>
#include<iostream>
using namespace std;
const int N = 210;//将n的环化为2n的链
int n;
int w[N];
int f[N][N];
int main()
{
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> w[i];
w[i + n] = w[i];//依次copy前面的
}
//枚举区间长度,区间最短为3,因为最终是合成长度为2的区间。
for (int len = 3; len <= n + 1; ++len) {
//枚举左端点
for (int l = 1; l + len - 1 <= n + 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 l = 1; l <= n; l++) {
ans = max(ans, f[l][l + n]);
}
cout << ans << endl;
return 0;
}
凸多边形的划分

思路:抽象成区间dp是一个非常重要的过程

样例输入:
5
121 122 123 245 231
样例输出:
12214884
代码模板:
//未加高精度
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N = 55,INF = 1e9;
int n,w[N];
int f[N][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;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]);
cout<<l<<" "<<r<<" "<<f[l][r]<<endl;
}
cout<<f[1][n]<<endl;
return 0;
}
加分二叉树

样例输入:
5
5 7 1 2 10
样例输出:
145
3 1 2 4 5
代码模板:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 50;
int n;
int w[N];
unsigned f[N][N];
int root[N][N];
void dfs(int l, int r)
{
if (l > r) return;
int k = root[l][r];
printf("%d ", k);
dfs(l, k - 1);
dfs(k + 1, r);
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
for (int len = 1; len <= n; len ++ )
for (int l = 1; l + len - 1 <= n; l ++ )
{
int r = l + len - 1;
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 score = left * right + w[k];
if (l == r) score = w[k];
if (f[l][r] < score)
{
f[l][r] = score;
root[l][r] = k;
}
}
}
printf("%d\n", f[1][n]);
dfs(1, n);
puts("");
return 0;
}
棋盘分割(记忆式搜索)

样例输入:
3
1 1 1 1 1 1 1 3
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 0
1 1 1 1 1 1 0 3
样例输出:
1.633
代码模板:
//记忆式搜索
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 15, M = 9;
const double INF = 1e9;
int n, m = 8;
int s[M][M];
double f[M][M][M][M][N];//将矩阵(x1,y1)(x2,y2)分为k部分的方案的最小值
double X;
int get_sum(int x1, int y1, int x2, int y2) //矩阵和
{
return s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1];
}
double get(int x1, int y1, int x2, int y2)//上述公式
{
double sum = get_sum(x1, y1, x2, y2) - X;
return (double)sum * sum / n;
}
double dp(int x1, int y1, int x2, int y2, int k)
{
double &v = f[x1][y1][x2][y2][k];
if (v >= 0) return v;
if (k == 1) return v = get(x1, y1, x2, y2);
v = INF;
for (int i = x1; i < x2; i ++ )//分割分成两部份,分别dp
{
v = min(v, get(x1, y1, i, y2) + dp(i + 1, y1, x2, y2, k - 1));
v = min(v, get(i + 1, y1, x2, y2) + dp(x1, y1, i, y2, k - 1));
}
for (int i = y1; i < y2; i ++ )//同
{
v = min(v, get(x1, y1, x2, i) + dp(x1, i + 1, x2, y2, k - 1));
v = min(v, get(x1, i + 1, x2, y2) + dp(x1, y1, x2, i, k - 1));
}
return v;
}
int main()
{
cin >> n;
for (int i = 1; i <= m; i ++ )
for (int j = 1; j <= m; j ++ )
{
cin >> s[i][j];
s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
}
X = (double)s[m][m] / n;
memset(f, -1, sizeof f);
printf("%.3lf\n", sqrt(dp(1, 1, 8, 8, n)));
return 0;
}

浙公网安备 33010602011771号