石子合并问题(动态规划)

一条直线上摆放着一行共n堆的石子。现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆石子数记为该次合并的得分。

请编辑计算出将n堆石子合并成一堆的最小得分和将n堆石子合并成一堆的最大得分。

Input

输入有多组测试数据。

每组第一行为n(n<=100),表示有n堆石子,。

二行为n个用空格隔开的整数,依次表示这n堆石子的石子数量ai(0<ai<=100)

Output

每组测试数据输出有一行。输出将n堆石子合并成一堆的最小得分和将n堆石子合并成一堆的最大得分。 中间用空格分开。

间用空格分开。

Sample Input

3

1 2 3

Sample Output

9 11

 1 #include<iostream>
 2 #include <cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define INF 0x3f3f3f3f
 7 
 8 int dp[105][105];
 9 int sum[110];
10 int ans=0,cnt=0;
11 
12 int dfs(int l,int r){/*求最大*/
13     if(dp[l][r]!=-1){
14         return dp[l][r];
15     }
16     if(r-l==1)return sum[r]-sum[l-1];
17     if(r==l) return 0;
18     int &res=dp[l][r];
19     res=-INF;
20     for(int k=l;k<r;k++){
21         res=max(res,dfs(l,k)+dfs(k+1,r));
22     }
23     res+=sum[r]-sum[l-1];
24     return res;
25 }
26 
27 int dfs2(int l,int r){/*求最小*/
28    if(dp[l][r]!=-1) return dp[l][r];
29    if(r-l==1) return sum[r]-sum[l-1];
30    if(r==l) return 0;
31    dp[l][r]=INF;
32    for( int k=l; k<r; k++ ){
33         dp[l][r]=min(dp[l][r],dfs2(l,k)+dfs2(k+1,r));
34    }
35    dp[l][r]+=sum[r]-sum[l-1];
36    return dp[l][r];
37 }
38 
39 int main(){
40     int n;
41     memset(sum,0,sizeof(sum));
42     while(~scanf("%d",&n)&&n){
43         for( int i=1; i<=n; i++ ){
44             int t;
45             cin>>t;
46             sum[i]=sum[i-1]+t;
47         }
48         memset(dp,-1,sizeof(dp));
49         ans=dfs2(1,n);
50         memset(dp,-1,sizeof(dp));
51         cnt=dfs(1,n);
52         cout<<ans<<" "<<cnt<<endl;
53     }
54 
55     return 0;
56 }
有些目标看似很遥远,但只要付出足够多的努力,这一切总有可能实现!
原文地址:https://www.cnblogs.com/Bravewtz/p/10497087.html