合并石子----动态规划

Description

在操场上沿一直线排列着 n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆石子合并成新的一堆, 并将新的一堆石子数记为该次合并的得分。允许在第一次合并前对调一次相邻两堆石子的次序。

计算在上述条件下将n堆石子合并成一堆的最小得分。

Input

输入数据共有二行,其中,第1行是石子堆数n≤100;
第2行是顺序排列的各堆石子数(≤20),每两个数之间用空格分隔。

Output

输出合并的最小得分。

Sample Input

3 2 5 1

Sample Output

11

相信大多数人看到这道题第一反应就是直接贪心,每次都选最小的两堆合并,每次都是最小那最后不也是最小,但实际上每次的最优解并一定是最终的最优解,因为你无法预知接下来剩下的合成解是否也是最优

换一个角度,最后一次合并就是把上一次合并剩下的两堆合并成一堆,再加上这个区间的和,再来观察这两个小堆其中一个,是不是跟最后和并的大堆实际上是一个东西,而我们是不是只要保证两个小堆的合成是最优,那么合并出来的大堆也就是最优,那么如何划分这两个小堆,那就是枚举划分点的位置x,把f[i][j]设为i到j的最优合并费用,可以得到f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+det),det就是i到j的区间和,因为把两个区间合并就是加上这两个区间的总和。

这一题的开始可以交换位置,这个好办,就枚举交换位置的数好了,不要忘记换回来。

下面代码和一些细节

#include<stdio.h>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define r(i,a,b)for(int i=1;i<=b;i++)
ll f[110][110];
ll sum[110];
int a[110];
int n;
void swap(int x, int y)
{
	int t;
	t = a[x], a[x] = a[y], a[y] = t;
	return;
}
void ini()
{
	r(i, 1, n)
		r(j, 1, n)
    {
     if(i==j)f[i][j]=0;//跟自己合并费用为零
        else f[i][j]=inf;//初始值设为无穷大
    }
	return;
}
int main()
{
	scanf("%d", &n);
	r(i, 1, n)scanf("%d",a+i);
	ll ans = inf;
	r(wz, 1, n - 1)
	{
		swap(wz, wz + 1);//交换两个相邻的位置
		ini();//对f数组初始化
		r(i, 1, n)sum[i] = a[i] + sum[i - 1];//前缀和辅助快速求区间和
        //r(i,1,n)printf("%lld ",sum[i]);printf("\n");
		r(l, 1, n - 1)//长度-1
		{
			for (int j = 1; j + l <= n; j++)
			{
				int k = j + l;//右边界
				ll det = sum[k] - sum[j - 1];
                //合并这一次必定要加上这个区间的和,两个区间合成一个长区间,得到这个区间和分数
				r(x, j , k-1)//枚举拆分数组,123 45这样拆成两个部分
					f[j][k] = min(f[j][k], f[j][x] + f[x + 1][k] + det);
			}
		}
         //printf("%lld\n",ans);
		ans = min(ans, f[1][n]);//计算交换这一轮下的最小值
		swap(wz, wz + 1);//换回来
	}
    printf("%lld\n",ans);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值