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 }