uva:10003 - Cutting Sticks

来源:互联网 发布:unity3d webplayer 编辑:程序博客网 时间:2024/06/06 02:02

题目链接: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 ;elsenum[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 ;}




原创粉丝点击