最小代价树

题目:
描述
以下方法称为最小代价的字母树:给定一正整数序列,例如:4,1,2,3,在不改变数的位置的条件下把它们相加,并且用括号来标记每一次加法所得到的和。
例如:((4+1)+ (2+3))=((5)+(5))=10。除去原数不4,1,2,3之外,其余都为中间结果,如5,5,10,将中间结果相加,得到:5+5+10=20,那么数20称为此数列的一个代价,若得到另一种算法:(4+((1+2)+3))=(4+((3)+3))=(4+(6))=10,数列的另一个代价为:3+6+10=19。若给出N个数,可加N-1对括号,求出此数列的最小代价。
注:结果范围不超出longint.
输入
第一行为数N(1≤N≤200),第二行为N个正整数,整数之间用空格隔开。
输出
输出仅一行,即为最少代价值。
样例输入
4
4  1  2  3
样例输出
19

分析:
该题类似石子合并问题:
在一条直线上摆着N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为将的一堆石子的数量。设计一个算法,将这N堆石子合并成一堆的总花费最小(或最大)。
如果熟悉矩阵连乘对这类问题肯定非常了解。矩阵连乘每次也是合并相邻两个矩阵(只是计算方式不同)。那么石子合并问题可用矩阵连乘的方法来解决。
那么最优子结构是什么呢?如果有N堆,第一次操作肯定是从n-1个对中选取一对进行合并,第二次从n-2对中选取一对进行合并,以此类推……
设f[i][j]表示i-j合并的最优值, sum[i][j]表示第i堆石子到第j堆石子的总数量,递推公式如下:

(矩阵连乘可见《算法导论》,讲的很详细)

 

下面给出代码:

#include <stdio.h>
#include <limits.h>

int N,arr[210],sum[210][210],m[210][210];

void calSum();
void calMinSum();

int main()
{
	int i;

	scanf("%d",&N);  //输入元素个数
	for (i=0;i<N;i++)
	{ 
		scanf("%d",&arr[i]);  //为数组赋值
	}

	calMinSum();  //计算最小代价和

	return 0;
}

void calSum()
{
	int i,j,k;

	for (i=0;i<N;i++)  //计算从i到j的元素和
	{
		for (j=i;j<N;j++)
		{
			for (k=i;k<=j;k++)
			{
				sum[i][j]+=arr[k];
			}
		}
	}
}

void calMinSum()
{
	int r,i,j,k,iTemp;  //r为链长

	calSum();

	for (i=0;i<N;i++)
	{
		m[i][i]=0;
	}

	for (r=2;r<=N;r++)
	{
		for (i=0;i<N-r+1;i++)
		{
			j=i+r-1;

			m[i][j]=INT_MAX;
			for (k=i;k<=j-1;k++)
			{
				iTemp=m[i][k]+m[k+1][j]+sum[i][j];

				if (iTemp<m[i][j])
				{
					m[i][j]=iTemp;
				}
			}
		}
	}

	printf("%d\n",m[0][N-1]);

}



 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值