假设有n堆石子需要合并,可以设计一个2*n-1个元素的数组来存储每堆石子的个数。 分析最优解的结构:假设有石头AiAi+1……Aj需要合并,简记为A[i,j].如果设最后一次合并发生在Ak与Ak+1之间(i<=k<j),则最后一个合并的得分为Ai……Aj堆石头的个数的总和记为totalValue(i,j).(不管你最后一次合并发生在哪个位置,totalValue(i,j)的值都是一样的)因此总的得分等于A[i,k]的得分加上A[k+1,j]的得分再加上totalValue(i,j). 可以假设计算A[0,n-1]的一个最优次序所包含的计算子链A[0,k]和A[K+1,n-1]的次序也是最优的. 证明: 假设存在一个比计算A[0,k]的次序得分更少的次序,则用此次序来替换原来计算A[0,k]的次序,那么此时计算A[0,n-1]次序的得分就会比最优次序所得到的分数更少,这与假设相矛盾;同理可证明:计算A[0,n-1]的一个最优次序所包含的另一个计算子链A[k+1,n-1]的次序也是最优的! 综上所述,此题满足最优子结构性质,因此可以用动态规划算法来求解. 建立递归关系 设m[i][j]表示A[i,j]的计算结果. 当i=j时,表示只有一堆石头,不能合并,因此得分为零,所以m[i,j]=0; 当i<j时,可利用最优子结构性质来计算m[i][j], m[i,j]=m[i,k]+m[k+1,j]+totalValue(i,j)(i<=k<j) 可用矩阵连乘的最优计算次序问题来求解这题.可选用自顶向下的备忘录算法或是自底向上的动态规划算法. 以下代码使用动态规划算法: void MatrixChain(int *p,int n,int **m,int flag) //矩阵连乘算法 { for(int i=0;i<n;i++) m[i][i]=0; for(int r=2;r<n;r++) for(int i=0;i<n-r+1;i++) { int j=i+r-1; int temp=totalValue(i,j,p); m[i][j]=m[i+1][j]+temp; for(int k=i+1;k<j;k++) { int t=m[i][k]+m[k+1][j]+temp; if(!flag) //求最小得分 { if(t<m[i][j]) m[i][j]=t; } else //求最大得分 if(t>m[i][j]) m[i][j]=t; } } } MatrixChain(inputNum,2*n-1,m,0); //计算最小得分 int resultMin=m[0][n-1]; for(i=1;i<=n-1;i++) if(resultMin>m[i][n-1+i]) resultMin=m[i][n-1+i]; MatrixChain(inputNum,2*n-1,m,1); //计算最大得分 int resultMax=m[0][n-1]; for(i=1;i<=n-1;i++) if(resultMax<m[i][n-1+i]) resultMax=m[i][n-1+i]; |