#include<bits/stdc++.h>
#define MAXN 10000+10
using namespace std;
int dp[MAXN][MAXN],s[MAXN][MAXN],cnt[MAXN];
int main(){
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&cnt[i]),cnt[i]=cnt[i-1]+cnt[i];
for(int i=1;i<=n;i++)
dp[i][i]=0,s[i][i]=i;
for(int i=n;i>=1;i--){
for(int j=i+1;j<=n;j++){
int temp=0x7fffffff;
int te;
for(int k=s[i][j-1];k<=s[i+1][j];k++){
if(temp>dp[i][k]+dp[k+1][j]+cnt[j]-cnt[i-1]){
temp=dp[i][k]+dp[k+1][j]+cnt[j]-cnt[i-1];
te=k;
}
}
dp[i][j]=temp;
s[i][j]=te;
}
}
cout<<dp[1][n]<<endl;
}
题目:
n 堆石子。现要将石子有次序地合并成一堆,规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并得分。设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分
算法:(注:代码石子首尾不连接)
设dp(i,j)定义为第i堆石子到第j堆石子合并后的最少总分数,想到这样dp转移
dp[i][j]=min{dp[i][k]+dp[k+1][j]}+cost[i][j]
cost[i][j]表示把第i堆到第j堆的石子和到一起的最后一步的代价,显然之前无论怎么合并,最后一步的代价都是一样的,所以我们可以先预处理出这个cost数组,他等于cnt[j]-cnt[i-1],其中cnt数组是前缀和,然后用四边形不等式优化
合并石子问题
现在有n堆石子,要将石子按一定顺序地合成一堆,规定如下,每次只能移动相邻的两堆石子,合并费用为新和成一堆石子的数量,求把n堆石子全部合并到一起所花的最少或者最大花费
很容易想到这样一个dp转移
dp[i][j]=min{dp[i][k]+dp[k+1][j]}+cost[i][j]
震惊!这不就是之前所讲的模型嘛?原来之前O(n^3)方的合并石子问题还可以优化(我太弱了)
首先明确一点,cost[i][j]表示把第i堆到第j堆的石子和到一起的最后一步的代价,显然,之前无论怎么合并,最后一步的代价都是一样的,所以我们可以先预处理出这个cost数组,他等于cnt[j]-cnt[i-1],其中cnt数组是前缀和
for一遍i,for一遍j,每算一次dp[i][j]还要for一遍k,自然是O(n^3)方,现在我们来按照规则判断是否可以用四边形优化
第一步(壹)证明cost为凸
对于所有的i,j,令其满足i< i+1<=j< j+1
我们需要证明
cost[i][j]+cost[i+1][j+1]<=cost[i+1][j]+cost[i][j+1]
移项
cost[i][j]-cost[i+1][j]<=cost[i][j+1]-cost[i+1][j+1]
令f(j)=cost[i][j]-cost[i+1][j]
f(j)=cnt[j]-cnt[i-1]-(cnt[j]-cnt[i])
f(j)=cnt[i]-cnt[i-1]
都跟j无关了,自然一定满足四边形不等式(这个时候是直接等于了,但没有违反四边形不等式)
第二步(贰)证明dp为凸
要推导dp[i][j]的凸性,自然要满足对任意的i,j,令i< i+1<=j< j+1
有如下结论
dp[i][j]+dp[i+1][j+1]<=dp[i+1][j]+dp[i][j+1]
令dp[i+1][j]取得最优值的时候k=x
令dp[i][j+1]取得最优值的时候k=y
令x < =y(之后还要令x > y,这里不再赘述,读者如有兴趣可以自行推导,方式相似)
将k=x代入dp[i][j],k=y代入dp[i+1][j+1]
左式=dp[i][x]+dp[x+1][j]+cost[i][j]+dp[i+1][y]+dp[y+1][j+1]+cost[i+1][j+1]①
而对于i< i+1<=j< j+1
由于已经在壹中证明了cost的凸性,所以
cost[i][j]+cost[i+1][j+1]<=cost[i+1][j]+cost[i][j+1]②
我们会发现这个不等式的左边在①式中出现过,所以把②式中的左式和右式替换一下可以得到如下结论
dp[i][x]+dp[x+1][j]+cost[i][j]+dp[i+1][y]+dp[y+1][j+1]+cost[i+1][j+1]
<=
dp[i][x]+dp[x+1][j+1]+cost[i][j+1]+dp[i+1][y]+dp[y+1][j]+cost[i+1][j]
即dp[i][j]+dp[i+1][j+1]<=dp[i][j+1]+dp[i+1][j]
证毕
第三步(叁)证明决策单调
现在我们已经证明了cost数组和dp数组的凸性,要证明决策单调以证明优化的正确性
即要证明s[i][j-1]<=s[i][j]<=s[i+1][j]
对于s[i][j-1]<=s[i][j]
令dp[i][j-1]取得最小值时的k=y,对于所有x≠y,令x<=y
可以有如下推导
∵x+1<=y+1<=j-1< j
四边形不等式有:
dp[x+1][j-1]+dp[y+1][j]<=dp[y+1][j-1]+dp[x+1][j]
在式子两边同时加上dp[i][x]+cost[i][j-1]+dp[i][y]+cost[i][j] 可以得到
dp[i][x]+dp[x+1][j-1]+cost[i][j-1]+dp[i][y]+dp[y+1][j]+cost[i][j]
<=
dp[i][x]+dp[x+1][j]+cost[i][j]+dp[i][y]+dp[y+1][j-1]+cost[i][j-1]
dp[i][j-1]+dp[i][j]<=dp[i][j]+dp[i][j-1]
(k=x)…………(k=y)……(k=x)……(k=y)
移项
dp[i][j-1]-dp[i][j-1]<=dp[i][j]-dp[i][j]
(k=x)…………(k=y)……(k=x)……(k=y)
由于我们是令k=y时dp[i][j-1]取得最小值,那么dp[i][j-1] (k=x)一定大于等于dp[i][j-1] (k=y),所以左式大于零,所以右式也大于零,所以对于dp[i][j-1]可以取到最优值的y,所有小于它的值,对于dp[i][j]来说,都没有y优,所以最优决策一定不是小于y的,如果令s[i][j]表示dp[i][j]取得最优值的时候的k值,那么一定有
s[i][j-1]<=s[i][j]
证毕