UVA 10003: Cutting Sitcks

本文通过解决切棍子问题介绍了动态规划的应用。首先尝试使用递归方法但出现超时,随后通过记忆化搜索优化并调整参数实现有效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态规划题。切棍子,类似矩阵连乘问题(Matrix Multiplication problem)。

当时我先写了一个比较简洁的递归代码,但是超时了。。。超时代码如下,虽然超时,但可以很好的体现出状态转移:

#define INF 50000
int c[50];

int dp(int left, int right, int cleft, int cright)
{
	if(cleft==cright) return 0;
	int min = INF;
	int tmp;
	for(int i=cleft; i<cright; i++)
	{
		tmp = dp(left,c[i],cleft,i)+dp(c[i],right,i+1,cright)+(right-left);
		if(min>tmp) min = tmp;
	}
	return min;
}
int main()
{
	int L,N;
	while(cin >> L && L)
	{
		cin >> N; 
		for(int i=0; i<N; i++) cin >> c[i];

		cout << "The minimum cutting is " << dp(0,L,0,N) << ".\n";
	}
	return 0;
}

dp的参数left,right表示当前处理的棍子左右端点在原棍子中的位置,cleft,cright表示当前这段棍子中需要切开的位置的编号(即c[cleft],c[cright]是要切开的位置)。

这段代码超时后想到需要记忆化,但dp有四个参数,难道要开四维数组?再想想发现left,right参数与cleft,cright参数的设置有点重复的感觉,因为棍子切开的位置就是下次处理切开后两段棍子的端点位置。于是在c数组的左右将0和L加入,看作0位置和L位置也是需要切开的位置,这样只需要cleft和cright两个参数就可以了。

于是稍稍改变一下超时代码得到了以下的AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
#define INF 50000
int c[52];
int mincost[52][52];
int dp(int i, int j)
{
	if(mincost[i][j]!=-1) return mincost[i][j];
	int min = INF, tmp;
	for(int k=i+1; k<j; k++)
	{
		tmp = dp(i,k)+dp(k,j)+(c[j]-c[i]);
		if(min>tmp) min = tmp;
	}
	return mincost[i][j] = min;
}
int main()
{
	int L,N;
	while(cin >> L && L!=0)
	{
		cin >> N; 
		for(int i=1; i<=N; i++) cin >> c[i];
		c[0] = 0; c[N+1] = L;
		memset(mincost,-1,sizeof(mincost));
		for(int i=0; i<=N; i++)
			mincost[i][i+1] = 0;//相邻两切口间的棍子不需要再切开,费用为0
		cout << "The minimum cutting is " << dp(0,N+1) << ".\n";

	}
	return 0;
}
mincost数组元素mincost[i][j]表示从i号切口到j号切口的那段棍子处理完毕需要的最小费用,它同时也是dp(i,j)的返回值。所求结果即dp(0,N+1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值