uvaoj 10003 Cutting Sticks 区间dp

题目的意思是有个长度为l的木棍,这个木棍需要加工n次,给出n次加工的位置,每次加工的花费是当前木棍的长度,求加工的最小花费。
与矩阵连乘多少有点类似,不过这里不是枚举最后一次切割的位置,这里最后一次切割的花费和之前的切割次序是相关的。所以不能这样枚举,但我们发现第一次切割时的花费是固定的,可以尝试一下枚举第一次切割的位置。用dp[i][j]代表第i次切割到第j次切割的最优值,我们可以得到这一段的总长度是pos[j+1]-pos[i-1],这里注意边界,要特殊处理下,然后枚举这一段第一次切割的位置k,转移方程为dp[i][j]=min(dp[i][k-1]+dp[k+1][j]+pos[j+1]-pos[i-1]),其中k为从i到j。这里也要注意边界的问题,当i大于j的时候dp[i][j]应该为0,其他的情况都应该初始化为一个足够大的值。只要注意号边界就可以了。这里有两种写法,一种是记忆化搜索,另一种是递推。
代码如下:
/*************************************************************************
	> File Name: 10003.cpp
	> Author: gwq
	> Mail: gwq5210@qq.com 
	> Created Time: 2014年11月09日 星期日 21时57分25秒
 ************************************************************************/

#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>

#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())

using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef long long ll;

const double esp = 1e-5;

#define N 55

int pos[N], len, n, dp[N][N], vis[N][N];

/*
 * 枚举第一次切割的位置,区间dp
 * 记忆化搜索,写法不好
 * 第l个切割位置到第r个切割位置的长度是pos[r + 1] - p[l - 1]
 * 处理好边界就行了
 */
int getans(int l, int r)
{
	if (dp[l][r] >= 0) {
		return dp[l][r];
	} else if (l == r) {
		return dp[l][r] = pos[r + 1] - pos[l - 1];
	} else if (l > r) {
		return dp[l][r] = 0;
	} else {
		dp[l][r] = INF;
		for (int k = l; k <= r; ++k) {
			int tmp = getans(l, k - 1) + getans(k + 1, r)
				+ pos[r + 1] - pos[l - 1];
			dp[l][r] = min(dp[l][r], tmp);
		}
		return dp[l][r];
	}
}

/*
 * 使用vis标记计算过的
 * 在边界的时候要注意当l大于r的时候,值应该是0,而且dp数组的
 * 初始化值应该是一个足够大的值
 */
int getans2(int l, int r)
{
	if (vis[l][r] == 1) {
		return dp[l][r];
	} else {
		vis[l][r] = 1;
		dp[l][r] = INF;		//可以在使用之前初始化
		for (int k = l; k <= r; ++k) {
			int tmp = getans2(l, k - 1) + getans2(k + 1, r)
				+ pos[r + 1] - pos[l - 1];
			dp[l][r] = min(dp[l][r], tmp);
		}
		if (l > r) {
			dp[l][r] = 0;
		}
		return dp[l][r];
	}
}

/*
 * 递推写法,也是先短后长
 */
int getans3(void)
{
	//初始化为足够大的值
	//当l大于r时初始化为0
	//因为这个是边界条件,可以简化转移方程
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < N; ++j) {
			dp[i][j] = (i > j) ? 0 : INF;
		}
	}
	for (int i = 0; i < n; ++i) {
		for (int j = 1; j + i <= n; ++j) {
			for (int k = j; k <= j + i; ++k) {
				int tmp = dp[j][k - 1] + dp[k + 1][j + i]
					+ pos[j + i + 1] - pos[j - 1];
				dp[j][j + i] = min(dp[j][j + i], tmp);
			}
		}
	}

	return dp[1][n];
}

int main(int argc, char *argv[])
{
	while (scanf("%d", &len) != EOF) {
		if (len == 0) {
			break;
		}
		scanf("%d", &n);
		//getans
		//clr(dp, -1);	
		//getans2
		//或者在之前总体初始化
		//clr(dp, 0x3f);
		clr(pos, 0);
		clr(vis, 0);
		pos[0] = 0;
		pos[n + 1] = len;
		for (int i = 1; i <= n; ++i) {
			scanf("%d", &pos[i]);
		}
		//保证位置是升序的
		sort(pos + 1, pos + 1 + n);
		//printf("The minimum cutting is %d.\n", getans(1, n));
		//printf("The minimum cutting is %d.\n", getans2(1, n));
		printf("The minimum cutting is %d.\n", getans3());
	}

	return 0;
}

/*
Cutting Sticks 
You have to cut a wood stick into pieces. The most affordable company,
The Analog Cutting Machinery, Inc. (ACM), charges money according to
the length of the stick being cut. Their procedure of work requires
that they only make one cut at a time.

It is easy to notice that different selections in the order of cutting
can led to different prices. For example, consider a stick of length
10 meters that has to be cut at 2, 4 and 7 meters from one end. There
are several choices. One can be cutting first at 2, then at 4, then at
7. This leads to a price of 10 + 8 + 6 = 24 because the first stick was
of 10 meters, the resulting of 8 and the last one of 6. Another choice
could be cutting at 4, then at 2, then at 7. This would lead to a price
of 10 + 4 + 6 = 20, which is a better price.

Your boss trusts your computer abilities to find out the minimum cost for
cutting a given stick.

Input 
The input will consist of several input cases. The first line of each test
case will contain a positive number l that represents the length of the
stick to be cut. You can assume l < 1000. The next line will contain
the number n (n < 50) of cuts to be made.

The next line consists of n positive numbers ci ( 0 < ci < l) representing
the places where the cuts have to be done, given in strictly increasing order.

An input case with l = 0 will represent the end of the input.

Output 
You have to print the cost of the optimal solution of the cutting problem,
that is the minimum cost of cutting the given stick. Format the output
as shown below.

Sample Input 
100
3
25 50 75
10
4
4 5 7 8
0

Sample Output 
The minimum cutting is 200.
The minimum cutting is 22.
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值