您的位置:首页 > 其它

石子合并 nyoj737 区间dp

2017-07-18 19:09 281 查看

题意:

有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,并将新的一堆石子数记为该次合并的代价。求最小代价。

思路

我们假设dp[i][j]是从i到j区间的最优解。

我们想知道,能否像建塔一样,知道了底层的就可以建立高层的。

这里我们以 j-i 的值为dp分层,也就是分为区间长度为1的,2的,3的…n的。

一个问题摆在面前,能否用低层次的砌高层次的。显然是可以的,这也是比较重要的地方。

很显然一个大的区间,必然是由构成他的,两个小的区间构成,比如区间[2 5],必然是有下列三对 区间 之一组合构成:[2 2][3 5] ; [2 3][4 5] ; [2 4][5 5];

总结一下,求区间dp[i][j]=min{dp[i][j+k]+dp[k+1][j]+代价函数} 其中(k=0,1,2…j-i )。

以下是参考代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
int dp[205][205];
int an[205];
int cn[205];
int sum(int a,int b){
return cn[b]-cn[a-1];
}
int minn(int a,int b){
return a<b? a:b;
}
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++) scanf("%d",&an[i]);
memset(cn,0,sizeof(cn));
for(int i=1;i<=n;i++) cn[i]=cn[i-1]+an[i];
memset(dp,0,sizeof(dp));

for(int i=1;i<n;i++){ //枚举区间长度 i+1
for(int j=1;j+i<=n;j++){//枚举区间左端点
for(int k=1;k<=i;k++){//枚举分割点,前k个为一组
if(dp[j][j+i]==0)  dp[j][j+i]=dp[j][j+k-1]+dp[j+k][j+i]+sum(j,j+i);
dp[j][j+i]=minn(dp[j][j+i],dp[j][j+k-1]+dp[j+k][j+i]+sum(j,j+i)); //状态转移方程
}
}
}

printf("%d\n",dp[1]
);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm