首先来个题目链接:http://acm.uestc.edu.cn/#/problem/show/886
题目:
方老师金币堆
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
虽然方老师赚到了很多钱,但是有些钱却非常难处理,经常会有人会以一大袋金币的方式来支付方老师的演讲报酬。现在方老师家里已经放置了N袋金币了,每一袋金币质量为Ai,他想把这些金币合并在一袋里面,然后存到银行去,于是方老师把这N袋金币围成一个圈,每一次他可以把相邻两袋金币合并,并消耗两袋金币质量总和的体力,他想让你帮他算下,他最少消耗多少体力可以完成这项工作。
注意:开始时第i袋金币与第i+1袋金币相邻,第1袋金币与第N袋金币相邻。
Input
输入有多组数据
每组数据第一行有1个正整数N,表示有N袋金币(1≤N≤100)
每组数据第二行N个整数,第i个整数表示第i袋金币的质量为Ai(1≤Ai≤50)
Output
输出1个整数,表示方老师最少消耗的体力。
Sample input and output
Sample Input | Sample Output |
---|---|
4 1 1 1 1 |
8 |
思路:dp[i][r]=min(dp[i][r],dp[i][k-1]+dp[(i+k-1)%n+1][r-k])。其中,dp[i][r]表示第i堆到第i+r堆的最优解。
最朴素的算法:

1 #include <fstream> 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cmath> 7 using namespace std; 8 9 const int N=205; 10 const int INF=0x7fffffff; 11 int n; 12 int a[N],sum[N],dp[N][N]; 13 14 int f(); 15 16 int main(){ 17 //freopen("D:\input.in","r",stdin); 18 while(~scanf("%d",&n)){ 19 sum[0]=0; 20 for(int i=1;i<=n;i++){ 21 scanf("%d",&a[i]); 22 sum[i]=sum[i-1]+a[i]; 23 } 24 printf("%d ",f()); 25 } 26 return 0; 27 } 28 int f(){ 29 for(int i=1;i<=n;i++) dp[i][0]=0; 30 for(int r=1;r<n;r++){ 31 for(int i=1;i<=n;i++){ 32 int j=i+r; 33 dp[i][r]=INF; 34 for(int k=1;k<=r;k++){ 35 if(i+k>n) dp[i][r]=min(dp[i][r],dp[i][k-1]+dp[(i+k)%n][r-k]); 36 else dp[i][r]=min(dp[i][r],dp[i][k-1]+dp[i+k][r-k]); 37 } 38 if(i+r>n) dp[i][r]+=sum[(i+r)%n]+sum[n]-sum[i-1]; 39 else dp[i][r]+=sum[i+r]-sum[i-1]; 40 } 41 } 42 int ans=INF; 43 for(int i=1;i<=n;i++) ans=min(ans,dp[i][n-1]); 44 return ans; 45 }
四边形不等式优化:

1 #include <fstream> 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cmath> 7 using namespace std; 8 9 const int N=205; 10 const int INF=0x7fffffff; 11 int n; 12 int a[N],sum[N],dp[N][N],s[N][N]; 13 14 int f(); 15 16 int main(){ 17 //freopen("D:\input.in","r",stdin); 18 while(~scanf("%d",&n)){ 19 sum[0]=0; 20 for(int i=1;i<=n;i++){ 21 scanf("%d",&a[i]); 22 sum[i]=sum[i-1]+a[i]; 23 } 24 printf("%d ",f()); 25 } 26 return 0; 27 } 28 int f(){ 29 for(int i=1;i<=n;i++) dp[i][0]=0,s[i][0]=1; 30 for(int r=1;r<n;r++){ 31 for(int i=1;i<=n;i++){ 32 int j=i+r; 33 dp[i][r]=INF; 34 for(int k=s[i][r-1];k<=s[i+1][r-1]+1;k++){ 35 int t=dp[i][k-1]+dp[(i+k-1)%n+1][r-k]; 36 if(dp[i][r]>t){ 37 dp[i][r]=t; 38 s[i][r]=k; 39 } 40 } 41 if(i+r>n) dp[i][r]+=sum[(i+r)%n]+sum[n]-sum[i-1]; 42 else dp[i][r]+=sum[i+r]-sum[i-1]; 43 } 44 } 45 int ans=INF; 46 for(int i=1;i<=n;i++) ans=min(ans,dp[i][n-1]); 47 return ans; 48 }
关于四边形不等式优化,详见:http://www.cnblogs.com/jiu0821/p/4493497.html