CSUOJ 1952 合并石子

现在有n堆石子,第i堆有ai个石子。现在要把这些石子合并成一堆,每次只能合并相邻两个,每次合并的代价是两堆石子的总石子数。求合并所有石子的最小代价。

 

Input

第一行包含一个整数T(T<=50),表示数据组数。
每组数据第一行包含一个整数n(2<=n<=100),表示石子的堆数。
第二行包含n个正整数ai(ai<=100),表示每堆石子的石子数。

 

Output

每组数据仅一行,表示最小合并代价。

 

Sample Input

2
4
1 2 3 4
5
3 5 2 1 4

Sample Output

19
33
题解:区间DP,dp[i][j]表示以i开始区间为j长的费用最小值;则状态转移方程为:dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<stack>
 8 #include<map>
 9 #include<vector>
10 #include<cstdlib>
11 #include<set>
12 using namespace std;
13 typedef long long LL;
14 const int INF=0x3f3f3f3f;
15 int T,N,w[110],dp[110][110],pre[110];
16 
17 int main()
18 {
19     ios::sync_with_stdio(false);
20     cin.tie(0);
21     cin>>T;
22     while(T--)
23     {
24         memset(dp,0,sizeof dp);
25         memset(pre,0,sizeof pre);
26         cin>>N;
27         for(int i=1;i<=N;i++) cin>>w[i],pre[i]=pre[i-1]+w[i];
28         
29         for(int i=1;i<=N;i++)
30         {
31             for(int j=1;j<=N-i;j++)
32             {
33                 dp[j][j+i]=INF;
34                 for(int k=j;k<=j+i-1;k++)
35                     dp[j][j+i]=min(dp[j][j+i],dp[j][k]+dp[k+1][j+i]+pre[j+i]-pre[j-1]);    
36             }
37         }
38         cout<<dp[1][N]<<endl;
39     }
40     
41     
42     return 0;
43 }
View Code

 

posted @ 2018-08-03 19:19  StarHai  阅读(296)  评论(0编辑  收藏  举报