[UVA 10003]Cutting Sticks[DP]

题目链接: [UVA 10003]Cutting Sticks[DP]
题意分析:给出一根木棍,然后需要对其进行切割,每一次切割费用是被切割木棍的长度。比如长度为10米,在4米处切割,因为被切割的木棍长度为10米,所以费用为10。问:升序给出所有要切割的点,最少的切割费用是多少?
解题思路:状态:dp[i][j]表示切割区间[i,j]所需要的最少费用;转移:dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + j - i + 1) (k是i、j包含的需要切割的点);边界:当区间中不存在需要切割的点时,费用为0。当i>j时,不存在这种切割,返回0(说明这种切割不影响结果)。
个人感受:感觉DP真是个神奇的东西,首先得知道状态,状态知道了,还得知道怎么转移,转移知道了还得知道怎么编码XD。不过正确的状态建立是一切的基石啊~这题看到紫书上的状态就懂了。。。。然后自己写了个搓搓的版本,时间1.8s。但也写份题解,好让网上的代码多出一种版本XD
具体代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 61;
int n,l;
bool cut[1111]; //代表:能切嘛?能切嘛?
int dp[1111][1111];

bool have(int l, int r) //检查区间是否有切割点
{
	for (int i = l; i <= r; ++i)
		if (cut[i]) return 1;
	return 0;
}

int dfs(int l, int r)
{
	int &ret = dp[l][r];
	if(!have(l,r)) return ret = 0; //没有切割点
	if(l > r ) return ret = 0; //无效区间
	if(ret < INF) return ret;
	for (int i = 1; i <= r; ++i)
	{
		if (cut[i])
		{
  			cut[i] = 0;
			ret = min(ret, dfs(l, i) + dfs(i + 1, r) + r - l + 1);
  			cut[i] = 1;
		}
	}
	return ret;
}

int main()
{
	while (cin >> l && l)
	{
		int x;
		cin >> n;
		memset(cut, 0, sizeof cut);
		memset(dp, 0x3f, sizeof dp);
		for (int i = 0; i < n; ++i) cin >> x, cut[x] = 1;
		int ans = INF;
		cout << "The minimum cutting is " << dfs(1, l) << ".\n";
	}
	return 0;
}

你可能感兴趣的:(dp,uva)