题目描述
有n堆石子,第i堆数量为ai(i=1,...i<=n);合并第i堆和第j堆的代价为ai+aj(只能相邻的两堆合并),然后两堆石子变为一堆,大小为ai+aj;
求合并n堆石子的最小代价与最大代价;
输入
n代表堆数,下面有a1.....an,表示每堆的数量;(2<=n<350),(0<=ai<=100);
输出
两个数,分别代表最小代价和最大代价,中间用空格隔开;
样例输入
4 36 17 3 24
样例输出
144 189
这个题是一个很经典的动态规划问题,大致在网上看了看,这个题有很多种形势,有的是环形的相邻的合并,有的是任意合并,但总体思路是一样的,就是矩阵连乘的思路。下面给出递推式:
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> using namespace std; long long dp[1005][1001]; long long sum[1000]; long long num[1000]; int n; int main(){ int l; int i,j,k; long minAns; long maxAns; scanf("%d",&n); memset(dp,0,sizeof(dp)); memset(sum,0,sizeof(sum)); for(int i=1;i<=n;i++){ scanf("%lld",&num[i]); sum[i]=sum[i-1]+num[i]; } for(l=2;l<=n;l++){ for(i=1;i<=n;i++){ j=i+l-1; if(j>n) continue; for(k=i;k<j;k++){ dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]); } } } maxAns=dp[1][n]; for(i=0; i<=n; i++) for(j=0;j<=n;j++) dp[i][j]=99999999; for(i=0;i<=n;i++) dp[i][i]= 0; for( l= 2;l<=n;l++) { for(i=1;i<=n;i++) { j=i+l-1; if(j>n) break; for(k=i;k<j;k++) { dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]); } } } minAns=dp[1][n]; printf("%lld %lld",minAns,maxAns); return 0; }