石子合并问题(动态规划)
一条直线上摆放着一行共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 }
有些目标看似很遥远,但只要付出足够多的努力,这一切总有可能实现!