石子合並問題(動態規划)


一條直線上擺放着一行共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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM