区间-dp
\(\text{poj-1651}\)
给定长度为 \(n\) 的序列 \(a\),将进行 \(n - 2\) 次操作:
- 选择一个下标 \(i \in [2, m - 1]\),其中 \(m\) 为当前序列长度。
- 代价增加 \(a_{i - 1} \cdot a_i \cdot a_{i + 1}\)。
- 从序列中删除 \(a_i\)。
求进行完 \(n - 2\) 次操作,代价的最小值。
\(3 \le n \le 100\)。
区间 dp 模板题。
令 \(f_{l,r}\) 表示删除 \(a_{l+1}, \dots, a_{r-1}\) 的最小代价。
初始化如下:
那么转移方程也很显然了:
最后答案即为 \(f_{1,n}\)。
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MAXN 105
#define INF 0x3f3f3f3f
ll read() {
ll x = 0, f = 1;
char c = getchar();
while(c < 48 || c > 57) { if(c == 45) f = -1; c = getchar(); }
while(c >= 48 && c <= 57) { x = (x << 3) + (x << 1) + (c - 48); c = getchar(); }
return x * f;
}
ll n, a[MAXN], dp[MAXN][MAXN];
int main() {
n = read();
for(int i = 1; i <= n; i ++) a[i] = read();
for(int len = 3; len <= n; len ++)
for(int l = 1; l + len - 1 <= n; l ++) {
ll r = l + len - 1; dp[l][r] = INF;
for(int k = l + 1; k < r; k ++)
dp[l][r] = min(dp[l][r], dp[l][k] + dp[k][r] + a[l] * a[k] * a[r]);
}
cout << dp[1][n] << "\n";
return 0;
}
\(\text{loj-10147}\)
将 \(n\) 堆石子绕圆形操场排放,现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。
请编写一个程序,读入堆数 \(n\) 及每堆的石子数,并进行如下计算:
- 选择一种合并石子的方案,使得做 \(n-1\) 次合并得分总和最大。
- 选择一种合并石子的方案,使得做 \(n-1\) 次合并得分总和最小。
\(1 \le n \le 200\)。
区间 dp 模板题。
和 poj-1651 的整体思路差不多。转移方程如下:
其中,求和可以用前缀和优化。答案为 \(\min\limits_{i=1}^n f_{i,i+n,0}\),\(\max\limits_{i=1}^n f_{i,i+n,1}\)。
总时间复杂度为 \(O(n^3)\)。
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MAXN 405
#define INF 0x3f3f3f3f
ll read() {
ll x = 0, f = 1;
char c = getchar();
while(c < 48 || c > 57) { if(c == 45) f = -1; c = getchar(); }
while(c >= 48 && c <= 57) { x = (x << 3) + (x << 1) + (c - 48); c = getchar(); }
return x * f;
}
ll n, a[MAXN], mn[MAXN][MAXN], mx[MAXN][MAXN], p[MAXN];
int main() {
n = read();
for(int i = 1; i <= n; i ++) a[i + n] = a[i] = read();
for(int i = 1; i <= 2 * n; i ++) p[i] = p[i - 1] + a[i], mn[i][i] = mx[i][i] = 0;
for(int len = 2; len <= n; len ++) for(int l = 1; l + len - 1 <= 2 * n; l ++) {
ll r = l + len - 1; mn[l][r] = INF, mx[l][r] = 0;
for(int k = l; k < r; k ++)
mn[l][r] = min(mn[l][r], mn[l][k] + mn[k + 1][r] + p[r] - p[l - 1]),
mx[l][r] = max(mx[l][r], mx[l][k] + mx[k + 1][r] + p[r] - p[l - 1]);
}
ll maxn = 0, minn = INF;
for(int i = 1; i <= n; i ++)
maxn = max(maxn, mx[i][i + n - 1]),
minn = min(minn, mn[i][i + n - 1]);
cout << minn << "\n" << maxn << "\n";
return 0;
}
\(\text{loj-10148}\)
原题来自:NOIP 2006
在 Mars 星球上,每个 Mars 人都随身佩带着一串能量项链。在项链上有 \(N\) 颗能量珠。能量珠是一颗有头标记和尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记必定等于后一颗珠子的头标记。因为只有这样,通过吸盘——Mars 人吸收能量的器官的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可被吸盘吸收的能量。如果一颗能量珠头标记为 \(m\),尾标记为 \(r\),后一颗能量珠头标记为 \(r\),尾标记为 \(n\),则聚合后释放出 \(m\times r\times n\) Mars单位的能量,新珠子头标记为 \(m\),尾标记为 \(n\)。
当需要时,Mars 人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不一样的。请设计一个聚合顺序使得一串珠子聚合后释放出的总能量最大。
例如,设 \(N=4\),四颗珠子头标记与尾标记分别为 \((2,3),(3,5),(5,10),(10,2)\)。我们用记号 \(\bigotimes\) 表示两颗珠子的聚合操作,\((j\bigotimes k)\) 表示 \(j,k\) 两颗珠子聚合后释放出的能量,则\(4,1\)两颗珠子聚合后所释放的能量为\((4\bigotimes 1)=10\times 2\times 3=60\),这一串项链可以得到最优值的一个聚合顺序所释放出的总能量为\((((4\bigotimes 1)\bigotimes 2)\bigotimes 3)=\) \(10\times 2\times 3+10\times 3\times 5+10\times 5\times 10=710\)
现在给你一串项链,项链上有 \(n\) 颗珠子,相邻两颗珠子可以合并成一个,合并同时会放出一定的能量,不同珠子合并放出能量不相同,请问按怎样的次序合并才能使得释放的能量最多?
\(4 \le n \le 100\)。
与 poj-1651 的唯一区别在于本题为环,因此只需要断环成链即可。
注意,本题要求最大值。
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MAXN 205
ll read() {
ll x = 0, f = 1;
char c = getchar();
while(c < 48 || c > 57) { if(c == 45) f = -1; c = getchar(); }
while(c >= 48 && c <= 57) { x = (x << 3) + (x << 1) + (c - 48); c = getchar(); }
return x * f;
}
ll n, a[MAXN], dp[MAXN][MAXN];
int main() {
n = read();
for(int i = 1; i <= n; i ++) a[i + n] = a[i] = read();
for(int len = 2; len <= n + 1; len ++) for(int l = 1; l + len - 1 <= 2 * n; l ++) {
ll r = l + len - 1; dp[l][r] = 0;
for(int k = l + 1; k < r; k ++)
dp[l][r] = max(dp[l][r], dp[l][k] + dp[k][r] + a[l] * a[k] * a[r]);
}
ll res = 0;
for(int i = 1; i <= n; i ++) res = max(res, dp[i][i + n]);
cout << res << "\n";
return 0;
}
本文来自博客园,作者:So_noSlack,转载请注明原文链接:https://www.cnblogs.com/So-noSlack/p/19638730

浙公网安备 33010602011771号