石子合并问题

i问题:

经典的石子合并问题,不过现在简化为线性问题,而不是环形问题。

放着n堆石子(n<= 100),现要将石子有次序地合并成一堆。规定每次只能选取相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

比如

3 4 6 5 4 2

最后得到的结果为:61

分析:

经典的DP算法,代码如下:

其中通项式为:

a[i][j] = min{k | a[i][k] + a[k+1][j] + sum[i...j], k = i...j-1}

其中a[i][j]表示从第i堆到第j堆合并能够取到的最小值,将其分解为两部分,从i到k,以及从k+1到j,再加上两大堆合并的得分。

/*
 * nim_merge.cpp
 *
 *  Created on: 2012-11-4
 *      Author: happier
 */


#include <iostream>
#include <cstdlib>
#include <cstdio>
using namespace std;

#define MAX 100
#define MAX_VALUE 0x7fffffff

int a[MAX][MAX];
int array[MAX];

int nim_merge(int n)
{
	if(n <= 0)
		return -1;

	for(int i = 1; i <= n; i++)
	{
		a[i][i] = 0;
	}

	int i, j, t;
	int min;
	int sum;

	for(int k =1; k <= n-1; k++)	//确定步长
	{
		i = 1;		//画斜对角线
		j = i+k;	//j开始位置,然后i++和j++
		//计算i到j的最大值
		//a[i][j] = min{k|a[i][k] + a[k+1][j] + sum[i...j], k = i...j-1}
		while(i <=n && j <=n)
		{
			min = MAX_VALUE;
			for( t = i; t <j; t++)
			{
				sum = a[i][t] + a[t+1][j];
				if(sum  < min)
					min = sum;
			}

			sum = 0;
			for( t= i; t <=j; t++)
				sum += array[t];	//最后合并的总和

			a[i][j] = min + sum;
			i++;
			j++;
		}
	}

	return a[1][n];
}

int main()
{
	int n;
	scanf("%d", &n);

	for(int i= 1; i <= n; i++)
	{
		scanf("%d", &array[i]);
	}

	std::cout << nim_merge(n) << endl;

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值