目录
初级版:51Nod - 1021 石子合并(区间dp,时间复杂度)
中级版:HDU - 3506 Monkey Party(四边形不等式优化,时间复杂度)
高级版:HYSBZ - 3229 石子合并(GarsiaWachs算法优化,时间复杂度常数小)
究极版:POJ - 1738 An old Stone Game(GarsiaWachs算法优化+平衡树优化,时间复杂度)
前言:
区间dp主要用于解决是将小区间合并成大区间的一种算法,通过断点的转移来合并区间以达到状态转移。比如石子合并就是通过对前缀和的操作,通过左端点和控制区间长度来进行的。
题目链接请点击题目
初级版:51Nod - 1021 石子合并(区间dp,时间复杂度
)
基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题
N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
例如: 1 2 3 4,有不少合并方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
Input
第1行:N(2 <= N <= 100)
第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)
Output
输出最小合并代价
Input示例
4
1
2
3
4
Output示例
19
思路:
通过前缀和记录区间和的情况,然后通过区间dp求解。
状态转移方程:![dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])(k\in [i,j])](https://private.codecogs.com/gif.latex?dp%5Bi%5D%5Bj%5D%3Dmin%28dp%5Bi%5D%5Bj%5D%2Cdp%5Bi%5D%5Bk%5D+dp%5Bk+1%5D%5Bj%5D+sum%5Bj%5D-sum%5Bi-1%5D%29%28k%5Cin%20%5Bi%2Cj%5D%29)
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
int wight[N],dp[107][107],w;
int main()
{
ios::sync_with_stdio(false);
int n;
cin >> n;
memset(dp,inf,sizeof dp);
memset(wight,0,sizeof wight);
for(int i = 1;i <= n;++i){
cin >> w;
wight[i] = wight[i - 1] + w;
dp[i][i] = 0;
}
for(int l = 1;l <= n;++l)
for(int i = 1;i + l <= n;++i){
int End = i + l;
for(int j = i;j <= End;++j)
dp[i][End] &