关闭

uva:10003 - Cutting Sticks

255人阅读 评论(0) 收藏 举报

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

这个题目开始的时候想正向处理,按照给定的点,不断的划分,但是发现状态转移有些小麻烦,就放弃了那种思路,昨天晚上在睡觉之前突然想到,可以逆向处理的,就是将这支树枝先按照指定的点切割,切割后,在组合起来,看组合的时候能使用的最少费用是多少,这样考虑的时候就最优矩阵链问题相同了,状态转移就很清楚了,动规方程如下:f(i , j) = min{ f(i ,k) , f(k+1 , j) + len(i , j)} 

其中f(i , j) 表示区间[i , j] 的最优值,len(i , j)表示这一区间的长度总和。

代码如下:

#include<iostream>
#include<stdio.h>
#include<string.h>

using namespace std ;

const int INF = 1000000 ;

int num[55][55] ;
int len[55] ;
int n ;
int length ;

int dp(int  , int ) ;
int dist(int , int) ;

int main()
{
//	freopen("in.txt" , "r" , stdin) ;
	while(cin>>length && length)
	{
		int i ;	
		int temp ;
		int k ;

		temp = 0 ;
		scanf("%d" , &n) ;
		//转化为段存储,每一段的长度可以求出
		for(i = 0 ; i < n ; i ++)
		{
			scanf("%d" , &len[i]) ;
			
			k = len[i] ;

			len[i] = len[i] - temp ;
			
			temp = k ;
		}
		len[i] =  length - temp ;

		for(i = 0 ; i <= n ; i ++)
		{
			for(int j = 0 ; j <= n ; j ++)
			{
				num[i][j] = INF ;
			}
		}
		cout<<"The minimum cutting is ";
		cout<<dp(0 , n)<<"."<<endl ;
	}
	return 0 ;
}

int dp(int left , int right)//记忆化搜索
{
	if(left==right)
		return 0 ;

	int & ans = num[left][right] ;

	if(ans < INF)
		return ans ;

	for(int i = left ; i <= right ; i ++)
	{
		if(ans > dp(left , i) + dp(i+1 , right) + dist(left , right) ) 
			ans = dp(left , i) + dp(i+1 ,right) + dist(left , right) ;
	}

	return ans ;
}

int dist(int i , int j)//求这一区间的总和
{
	int sum = 0 ;

	while(i <= j)
	{
		sum += len[i] ;
		i ++ ;
	}

	return sum ;
}

此外需要注意初值要赋为无穷大。

补充采用递推AC的源代码,用递推的时候,要注意阶段的表示,应该以j-i的值递增的顺序来计算。源代码如下:

#include <iostream>
#include <stdio.h>
#include <string.h>

using namespace std;
const int INF = 1000000 ;

int num[55][55] ;
int len[55] ;
int n ;
int length ;

int dist(int , int );

int main()
{
	//freopen("uva10003.txt" , "r" , stdin) ;

	int i ;
	int j ;
	int k ;
	int temp ;

	while(cin>>length && length)
	{
		temp = 0 ;
		scanf("%d" , &n) ;

		for(i = 0 ; i < n ; i ++)
		{
			scanf("%d" , &len[i]) ;

			k = len[i] ;

			len[i] = len[i] - temp ;

			temp = k ;
		}

		len[i] =  length - temp ;

		for(i = 0 ; i <= n ; i ++)
		{
			for(j = 0 ; j <= n ; j ++)
			{
				if(i!=j)
					num[i][j] = INF ;
				else
					num[i][j] =  0  ;
			}
		}

		for(temp = 0 ; temp <= n ; temp ++)//表示j-i的值,从0到n
		{

			for(i = 0 ; i <= n - temp ; i ++)
			{
				j = i + temp ;

				for(k = 0 ; k <= j ; k ++)
				{
					if(num[i][j] > num[i][k] + num[k+1][j] + dist(i , j))
						num[i][j] = num[i][k] + num[k+1][j] + dist(i , j) ;
				}
			}
		}

		printf("The minimum cutting is %d.\n" , num[0][n]) ;
	}
    return 0;
}

int dist(int i , int j)
{
	int sum = 0 ;

	while(i <= j)
	{
		sum += len[i] ;
		i ++ ;
	}

	return sum ;
}




0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:93267次
    • 积分:2458
    • 等级:
    • 排名:第15575名
    • 原创:167篇
    • 转载:1篇
    • 译文:0篇
    • 评论:0条