Uva10003 Cutting Sticks (DP_区间合并)

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=114&page=show_problem&problem=944


题目大意:给定一根长为l的木头,要求在木头的n个位置锯断它,每次锯断一段木头,就把这段木头的长度累加起来输出。


解题思路:如果不转换模型,这题很难想。顺着每次吧长度为li的木头锯成两段,将li累加,而后如果某段木头中间还需锯断,再累加lj,这样就相当于要去搜索,难做复杂度高。换个角度,其实每次累加就是两段的长度累加起来。原来最后几根中间不可以再锯的木头现在设想成最初的状态,如果两个木头可以合并,那么就把两个木头长度累加,现在问题转换为经典的石子合并问题,也就是区间合并问题。状态转移方程为:dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[i][j])(dp[i][j]表示从木头的i位置到j位置的累加和最少为多少,sum[i][j]表示i到j的长度)

     如果这题的木头锯断位置不是有序的,那么模型更难转换,那更有意思。


测试数据:

100
3
25 50 75

10
4
4 5 7 8


100

1

50


代码:

#include <stdio.h>
#include <string.h>
#define MAX 100
#define INF 1000000000


int  n,l,arr[MAX];
int  dp[MAX][MAX];
int sum[MAX][MAX];


int main()
{
	int i,j,k,tpk,tpsum;


	while (scanf("%d",&l),l) {

		scanf("%d",&n);
		arr[0] = 0,arr[n+1] = l;
		for (i = 1; i <= n; ++i)
			scanf("%d",&arr[i]);
		

		n = n + 1;
		memset(sum,0,sizeof(sum));
		for (i = 1; i <= n; ++i) {
		
			for (j = i; j <= n; ++j) {

				dp[i][j] = INF;
				sum[i][j] = arr[j] - arr[i-1];
			}
			dp[i][i] = 0;
		}


		for (k = 1; k < n; ++k) {
		//k为区间长度
			for (i = 1; i <= n - k; ++i) {
			//i表示第一个区间的开始位置
				j = i + k;
				for (tpk = i; tpk < j; ++tpk) {
				//tp+1表示另一个区间的开始位置
					if (dp[i][tpk] + dp[tpk+1][j] + sum[i][j] < dp[i][j])
						dp[i][j] = dp[i][tpk] + dp[tpk+1][j] + sum[i][j];
				}
			}
		}
		printf("The minimum cutting is %d.\n",dp[1][n]);
	}
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

你可能感兴趣的:(测试)