UVA 10003: Cutting Sitcks

来源:互联网 发布:淘宝申请售后退款 编辑:程序博客网 时间:2024/06/04 00:45

动态规划题。切棍子,类似矩阵连乘问题(Matrix Multiplication problem)。

当时我先写了一个比较简洁的递归代码,但是超时了。。。超时代码如下,虽然超时,但可以很好的体现出状态转移:

#define INF 50000int c[50];int dp(int left, int right, int cleft, int cright){if(cleft==cright) return 0;int min = INF;int tmp;for(int i=cleft; i<cright; i++){tmp = dp(left,c[i],cleft,i)+dp(c[i],right,i+1,cright)+(right-left);if(min>tmp) min = tmp;}return min;}int main(){int L,N;while(cin >> L && L){cin >> N; for(int i=0; i<N; i++) cin >> c[i];cout << "The minimum cutting is " << dp(0,L,0,N) << ".\n";}return 0;}

dp的参数left,right表示当前处理的棍子左右端点在原棍子中的位置,cleft,cright表示当前这段棍子中需要切开的位置的编号(即c[cleft],c[cright]是要切开的位置)。

这段代码超时后想到需要记忆化,但dp有四个参数,难道要开四维数组?再想想发现left,right参数与cleft,cright参数的设置有点重复的感觉,因为棍子切开的位置就是下次处理切开后两段棍子的端点位置。于是在c数组的左右将0和L加入,看作0位置和L位置也是需要切开的位置,这样只需要cleft和cright两个参数就可以了。

于是稍稍改变一下超时代码得到了以下的AC代码:

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define INF 50000int c[52];int mincost[52][52];int dp(int i, int j){if(mincost[i][j]!=-1) return mincost[i][j];int min = INF, tmp;for(int k=i+1; k<j; k++){tmp = dp(i,k)+dp(k,j)+(c[j]-c[i]);if(min>tmp) min = tmp;}return mincost[i][j] = min;}int main(){int L,N;while(cin >> L && L!=0){cin >> N; for(int i=1; i<=N; i++) cin >> c[i];c[0] = 0; c[N+1] = L;memset(mincost,-1,sizeof(mincost));for(int i=0; i<=N; i++)mincost[i][i+1] = 0;//相邻两切口间的棍子不需要再切开,费用为0cout << "The minimum cutting is " << dp(0,N+1) << ".\n";}return 0;}
mincost数组元素mincost[i][j]表示从i号切口到j号切口的那段棍子处理完毕需要的最小费用,它同时也是dp(i,j)的返回值。所求结果即dp(0,N+1)。

原创粉丝点击