Uva10003切木棍

题意:
题目的意思就是,有一根木根,长度为 l ,要给它n刀.分别在c1,c2,c3…cn的位置切.
每一刀的消费是当前这段木棍的长度.

比如长度10 , 要在2,4,7三个位置切.假设顺序是 4, 2 ,7.
切4这个位置的时候,木棍长度10 ,消耗10,然后切2这个位置的时候,它所在的地方木棍长度是4 ,消耗4,切7时消耗6.总共10 + 4 +6 = 20.
这种切法也是最省的,如果2.4.7要10 + 8 +6 =24.
题目就是要求最少消耗.

思路:区间DP
定义状态:D[ i ][ j ]:切第 i 到第 j 个切点的最小花费。 此时的花费怎么求?
比如第一次切,i = 1, j = n; 花费就是 j 的上界 减去 i 的下界,即A[j+1] - A[i-1]。这里两端节点左右是有延展的。所以我们加入两个虚拟切点,A[0] = 0,A[n+1] = s(初始木棍长度)。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int INF = 1<<30;
const int N = 50+5;

int s,n,A[N]; // 切割坐标 
int d[N][N];

int f(int i, int j){
	int& ans = d[i][j];
	if(ans > 0) return ans;
	if(i > j) return ans = 0;
	
	ans = INF;
	for(int k = i; k <= j; ++k){
		int up =  A[j+1];
		int down = A[i-1];
		ans = min(ans, f(i,k-1)+f(k+1,j)+up-down);
	}
	return ans;
}

int main()
{
	//freopen("in.txt","r",stdin);
	while(scanf("%d",&s) == 1&&s){
		
		memset(d,0,sizeof(d)); 
		int n; scanf("%d",&n);
		for(int i = 1; i <= n; ++i){
			scanf("%d",&A[i]);
		}
		A[0] = 0; A[n+1] = s;
		//递推初始化 
		
		for(int i = 1; i <= n; ++i){
			int up = A[i+1], down = A[i-1];
			d[i][i] = up - down;
		}
		/*
		for(int len = 1; len < n; ++len){ // 区间长度 
			for(int i = 1; i+len <= n; ++i){ // 区间起点
				int j = i + len;
				int up = A[j+1], down = A[i-1];
				d[i][j] = INF; 
				for(int k = i; k <= j; ++k){ // 枚举切割点
					 d[i][j] = min(d[i][j], d[i][k-1] + d[k+1][j] + up-down);
				}
			} 
		}
		int ans = d[1][n];
		*/
		int ans = f(1,n);
		 
		printf("The minimum cutting is %d.\n",ans);
	}

	return 0;
}

递推30ms,记忆化搜索150ms,差距比我想象中大一点。

猜你喜欢

转载自blog.csdn.net/CY05627/article/details/88426958