分 手 是 祝 愿 分手是祝愿 分手是祝愿
题目链接: j z o j 5263 jzoj\ 5263 jzoj 5263
题目
输入
输出
样例输入
2
2
15 19
3
30 40 20
样例输出
285
2600
数据范围
思路
这道题是区间dp。
我们设 T [ i ] [ j ] T[i][j] T[i][j] 是合并完第 i i i 个东西到第 j j j 个东西所需要多少魔力值,然后 M [ i ] [ j ] M[i][j] M[i][j] 为第 i i i 个东西到第 j j j 个东西合并到一起所产生的材料的魔力值。
那我们就可以dfs,每一次就枚举中间分开的点,分成两边,再分别dfs两边。
可以通过记忆化减少时间。
记得初始化。
代码
#include<cstdio>
#include<cstring>
using namespace std;
int TT, n, T[101][101], M[101][101], ans;
int work(int left, int right) {
if (T[left][right] >= 0) return T[left][right];//记忆化
for (int i = left; i < right; i++) {
int x = work(left, i);//左边
int y = work(i + 1, right);//右边
if ((x + y + M[left][i] * M[i + 1][right] < T[left][right]) || (T[left][right] == -1)) {//更加省力
T[left][right] = x + y + M[left][i] * M[i + 1][right];//替换
M[left][right] = (M[left][i] + M[i + 1][right]) % 100;//求出新材料的魔力值
}
}
return T[left][right];
}
int main() {
scanf("%d", &TT);//读入
for (int tim = 1; tim <= TT; tim++) {
memset(T, -1, sizeof(T));//初始化
scanf("%d", &n);//读入
for (int i = 1; i <= n; i++) {
scanf("%d", &M[i][i]);//读入
T[i][i] = 0;//初始化
}
ans = work(1, n);//动态规划
printf("%d\n", ans);//输出
}
return 0;
}