石子合并问题 --动态规划--解法1

在一个圆形操场的四周摆放着n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分。
 

假设有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];  

 

 

    原文作者:动态规划
    原文地址: https://blog.csdn.net/lyflower/article/details/2150239
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞