原命题链接:PDF/Vjudge


题目的意思是:告诉木棍的总长度,切点个数,和切点位置。每次切割花费的力气为切割的木棍的长度,求出最小花费的力气值。

还没怎么开始看dp,一开始看这道题目,想起了做过的一道拼接木块的题目,是用贪心AC的,本以为倒着写过去就完事,但是测试数据的时候发现,我去,差距太大了哦。后来一阵计算反思:贪心做不对,要动态规划。(贪心只能过样例)

没专业加仔细学习过动态规划的我,连蒙加猜加上数据找错,最后上交终于半夜AC,刚想一阵狼嚎马上闭住嘴了。


先放上代码兴奋一下:

#include <bits/stdc++.h>  
  
using namespace std;  
int a[500], dp[100][100];  
  
int dps(int left, int right)  
{  
    if (dp[left][right] >= 0)  
        return dp[left][right];  
    if (right - left == 1)  
        return 0;  
    int minx = 0xFFFFFFF;  
    for (int k = left + 1; k < right; k++)  
    {  
        minx = min(minx, dps(left,k) + dps(k,right) + a[right] - a[left]);  
        //cout << a[left] << " " << a[k] << " " << a[right] << " " << minx << endl;//测试的时候用的  
    }  
    return dp[left][right]= minx;  
}  
  
int main()  
{  
    int length;  
    while (cin >> length && length)  
    {  
        memset(a, 0, sizeof(a));  
        memset(dp, -1, sizeof(dp));  
        int cnt;  
        cin >> cnt;  
        for (int i = 1; i <= cnt; i++)  
            cin >> a[i];  
        a[cnt + 1] = length;  
        int ans = dps(0, cnt+1);  
        cout << "The minimum cutting is ";  
        cout << ans << "." << endl;  
        /*for (int i = 0; i < 5; i++)//测试的时候用的 
        { 
            for (int j = 0; j < 5; j++) 
                cout << " " << dp[i][j]; 
            cout << endl; 
        }*/  
    }  
    system("pause");  
    return 0;  
} 


思路重现:(大佬勿喷)
     一段木头,已知切点(我们可以把两头的位置也看作切点),我们要切割的话,

    如果只有一个切割点的话,是好求解的,

    我们可以用右端点减去左端点就得到花费的力气值,但是如果有多段呢?

    这里想到可以用二维数组的下标来的表示左切点和右切点来记录切割某一段区间的力气值。

    那么如果有多个切点呢,我们可以通过递归来找到某一段间隔区间的切割的力气值,如果没有储存当前区间,

    说明他要么是中间没有多余切点的切点(直接右端点减去左端点),要么是还没有计算(继续递归),

    这样的话,就可以得到每两个区间上的切割的最小力气值。

    最终的数值都是基于每一个区间上的最小的力气值,这样最后也是最小的力气值。

    采用递归的方式,一开始相当于最先着眼于每两个相邻的切点(最后一层递归终止),

    然后逐步扩大视野(到达上层递归),求出整个区间的力气值。

搬出一组(改了很久的)数据给自己以后看:

10  
3  
1 5 9  
5 9 10 5  
1 5 10 14  
1 5 9 8  
1 9 10 14  
0 1 10 24  
0 1 5 5  
0 5 10 20  
0 1 9 17  
0 5 9 14  
0 9 10 20  
The minimum cutting is 20.  
 -1 -1 5 14 20  
 -1 -1 -1 8 14  
 -1 -1 -1 -1 5  
 -1 -1 -1 -1 -1  
 -1 -1 -1 -1 -1  

下面是最后打出来的表(可能是这么叫。。。)

通过上面的思路应该可以看得出来

上方的输出就是切割某两个存在中间切点的切点的时候花费的最小力气值:

5 9 10 5 就是说,    从5-10在9处切点切割开来,花费的最小力气值是5.
1 5 10 14就是说,    从1-10在5切割开来花费的最小力气值是14,

怎么来的呢:1-10上有两个切点,要在5切开,这个时候的力气值肯定会有10-1=9,就是切割5花费的力气,

然后还需要5-10的力气值,上一行已经算出来了

就是5,加起来就是14.以此类推··· ···


最后

1.在写的时候一开始不是很严谨,定义minx的时候没有定义很大,导致出错,后来定义了一个大数就好了。

2.还有就是一开始没保存结果,就是没有dp那个数组,一直超时,后来才加上用数组下标来表示切点,减少递归次数。


FancyKing
8 声望0 粉丝