ACM第八周,动态规划区间DP(未完,待续)
区间DP和线性DP还是很相似的,线性dp是以一个点为对象,建立状态方程,在整个区间中找到最优解; 而区间dp则是以一个区间为对象,找出边界条件从小区间开始不断求解出最终总的区间问题。
区间DP主要是把一个大区间拆分成几个小区间,先求小区间的最优值,然后合并起来求大区间的最优值。
区间DP实现代码的一般规则:
}memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= n; i++)
dp[i][i] = 0;
for (int len = 2; len <= n; len++)
{
for (int i = 1, j = len; j <= n; i++, j++)
{
}
}
动态规划的区间DP问题主要分为三中模型。
石子问题
石子合并一条直线上有N堆石子,现在要将所有石子合并成一堆,每次只能合并相邻的两堆,合并花费为新合成的一堆石子的数量,求最小的花费。
题解:
当合并的石子为一堆时候:分数为0
当合并的石子为两堆时候:合并分数为相邻两堆石子的个数之和
当合并的石子为三堆时候:合并分数为min(第i堆石子与第i+1石子合并的分数+三堆石子总数,第i+1堆石子与第i+2石子合并的分数+三堆石子总数);
…
状态变量:m[i][j]第i堆至第j堆石子合并时候的分数,stone[i]表示第i堆石子个数
状态转移方程:m[i][j]=min(m[i][k]+m[k+1][j]+sum);sum表示第i堆石子至第j堆石子总数,也是最后一次合并的分数
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include <bits/stdc++.h>
using namespace std;
int w[105],dp[105][105],dp1[105][105],sum[105];
const int inf=0x3f;
int main()
{
int n;
while(cin>>n)
{
memset(dp,0,sizeof(dp));
memset(dp1,inf,sizeof(dp));
memset(sum,0,sizeof(sum));
for(int i=1; i<=n; i++)
{
cin>>w[i];
sum[i]=sum[i-1]+w[i];
dp1[i][i]=0;
}
for(int len=2; len<=n; len++)
{
for(int i=1; i<=n; i++)
{
int j=i+len-1;
for(int k=i; k<j; k++)
{
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
dp1[i][j]=min(dp1[i][j],dp1[i][k]+dp1[k+1][j]+sum[j]-sum[i-1]);
}
}
}
cout<<dp1[1][n]<<" "<<dp[1][n]<<endl;
}
return 0;
}