例题9-9 切木棍 UVa10003

1.题目描述:点击打开链接

2.解题思路:本题类似于动态规划中的“最优矩阵链相乘”问题——具有最优子结构。定义d(i,j)表示切割序号为i,j的切点处的小木棒的最优费用。用数组a存储切点的位置,则状态转移方程如下:

d(i,j)=min{d(i,k)+d(k,j)|i<k<j}+a[j]-a[i];

其中,a[j]-a[i]表示切割序号为i到j的小木棒的第一刀的费用。切完后,小木棒变为i~k,k~j两部分。如果设所有切点是1~n,左边界是0,右边界是n+1,那么本题答案是d(0,n+1)。本题的状态有O(N^2)个,每个状态的决策有O(N)个,总时间复杂度为O(N^3)。本题适合用递推写法来计算d(i,j),速度比记忆化写法更快,而且更方便。这里枚举变量是j-i,且要从小到大枚举。因为长区间的结果依赖短区间的结果。

3.代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;
#define INF 1000000
#define maxn 50+10
int L;
int n;
int ans;
int a[maxn];
int d[maxn][maxn];
int main()
{
	//freopen("test.txt", "r", stdin);
	while (scanf("%d", &L) == 1 && L)
	{
		memset(a, 0, sizeof(a));
		memset(d, 1000000, sizeof(d));
		scanf("%d", &n);
		for (int i = 1; i <= n; i++)
			scanf("%d", a + i);
		a[0] = 0;
		a[n + 1] = L;
		for (int i = 0; i < n + 1; i++)//计算长度为1的
			d[i][i + 1] = 0;
		for (int i = 0; i < n; i++)//长度为2的
			d[i][i + 2] = a[i + 2] - a[i];
		for (int len = 3; len <= n + 1; len++)//枚举长度
		for (int i = 0; i <= n + 1 - len; i++)
		{
			int j = i + len;
			for (int k = i + 1; k < j; k++)
			{
				int temp;
				temp = d[i][k] + d[k][j] + a[j] - a[i];
				d[i][j] = min(d[i][j], temp);
			}
		}
		printf("The minimum cutting is %d.\n", d[0][n+1]);
	}
	return 0;
}



时间: 2024-11-03 21:59:00

例题9-9 切木棍 UVa10003的相关文章

1442:【例题3】小木棍

1442:[例题3]小木棍 题解 从最优性方面: 1.设所有木棍长度和为maxn,那么原长度(也就是需要输出的长度)一定能够被maxn整除,这样得到的木棍根数才是整数2.木棍原来的长度一定不小于所有木棍中最长的那根综上两点,可以确定原木棍的长度len在最长木棍的长度minx和maxn之间取值,且maxn能被len整除.所以在搜索原木棍的长度时,可以从砍过以后所有木棍中最长的长度开始,每次增加长度后,必须能整除maxn.这样可以有效优化程序. 从可行性方面: 1.短木棍更加灵活,长木棍受到的限制更

UVA 10003 cuting sticks 切木棍

区间dp,切割dp[i][j]的花费和切法无关(无后效性) dp[i][j]表示区间i,j的花费,于是只要枚举切割方法就行了,区间就划分成更小的区间了.O(n^3) 看了看四边形不等式,证明太长了. #include<bits/stdc++.h> //变量不要取成ignore left之类 using namespace std; const int maxn = 51; int cut[maxn]; int dp[maxn][maxn]; const int INF = 0x3fffffff

1629 - Cake slicing(DP)

花了近2个小时终于AC,好爽.. 一道类似于最优矩阵链乘的题目,受<切木棍>那道题的启示,该题的原理也是一样的,仅仅只是变成了且面积.那么对应的也要添加维度 . 显然要完整的表示状态,最少要用四维数组.分别表示它的两个对角线顶点的坐标 .   然后横切或者纵切,递归需找更小的矩形,直到矩形内仅仅剩一个樱桃的时候返回0 那么问题就是如何高速的推断一个矩形内有多少个樱桃,于是决定再开一个数组记录这个矩形内樱桃的个数.一開始就是在这个地方超时(开了个五重循环) ,后来想到一个折中的办法,将时间复杂度

UVa10003 Cutting Sticks

考虑d(i,j)表示切割点i到j这段距离的最小花费,于是d(i,j)=min(d(i,k)+d(k,j))+a[j]-a[i] ,其中j<k<i,边界条件d(i,i)=d(i,i+1)=0,最终求d(0,n+1),复杂度o(n^3),可采用记忆化搜索. /*----UVa10003 Cutting Sticks 设d(i,j)为切割木棍(i,j)的最小费用,则d(i,j)=a[j]-a[i]+min{d(i,k)+d(k,j)} i<k<=j;最终求d(0,n+1) 为了方便,可以

【bzoj1044】[HAOI2008]木棍分割 二分+dp

题目描述 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007... 输入 输入文件第一行有2个数n,m.接下来n行每行一个正整数Li,表示第i根木棍的长度.n<=50000,0<=m<=min(n-1,1000),1<=Li<=1000. 输出 输出有2个数,

【BZOJ】1044: [HAOI2008]木棍分割 二分+区间DP

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1044 Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007... Input 输入文件第一行有2个数n,m. 接下来n行每行一个正整数Li,表示第i根木棍

木棍分割[HAOI2008]

题目描述 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007... 输入 输入文件第一行有2个数n,m.接下来n行每行一个正整数Li,表示第i根木棍的长度.n<=50000,0<=m<=min(n-1,1000),1<=Li<=1000. 输出 输出有2个数,

bzoj 1044 [HAOI2008]木棍分割(二分+贪心,DP+优化)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1044 [题意] n根木棍拼到一起,最多可以切m刀,问切成后最大段的最小值及其方案数. [思路] 对于第一问可以二分后贪心判断. 假设第一问得到的答案为L,设f[i][j]前i个木棍切j下且保持段长不超过L的方案数,则有转移式: f[i][j]=sigma { f[k][j-1] },k<i,suma(k+1,i)<=L 优化:  空间方面可以用个滚动数组. 时间方面由于前缀和sum

【BZOJ】【1044】【HAOI2008】木棍分割

二分/DP 真是一道好题! 第一问很简单的二分…… 第二问一开始我想成贪心了,其实应该是DP的= = 然后没有注意……又MLE又TLE的……这题要对DP进行时空两方面的优化!! 题解:(by JoeFan) 使用前缀和,令 Sum[i] 为前 i 根木棍的长度和. 令 f[i][j] 为前 i 根木棍中切 j 刀,并且满足最长长度不超过 j 的方案数,那么: 状态转移方程: f[i][j] = Σ f[k][j-1] ((1 <= k <= i-1) &&  (Sum[i] -