题目的意思是有个长度为l的木棍,这个木棍需要加工n次,给出n次加工的位置,每次加工的花费是当前木棍的长度,求加工的最小花费。
与矩阵连乘多少有点类似,不过这里不是枚举最后一次切割的位置,这里最后一次切割的花费和之前的切割次序是相关的。所以不能这样枚举,但我们发现第一次切割时的花费是固定的,可以尝试一下枚举第一次切割的位置。用dp[i][j]代表第i次切割到第j次切割的最优值,我们可以得到这一段的总长度是pos[j+1]-pos[i-1],这里注意边界,要特殊处理下,然后枚举这一段第一次切割的位置k,转移方程为dp[i][j]=min(dp[i][k-1]+dp[k+1][j]+pos[j+1]-pos[i-1]),其中k为从i到j。这里也要注意边界的问题,当i大于j的时候dp[i][j]应该为0,其他的情况都应该初始化为一个足够大的值。只要注意号边界就可以了。这里有两种写法,一种是记忆化搜索,另一种是递推。
代码如下:
/*************************************************************************
> File Name: 10003.cpp
> Author: gwq
> Mail: gwq5210@qq.com
> Created Time: 2014年11月09日 星期日 21时57分25秒
************************************************************************/
#include <cmath>
#include <ctime>
#include <cctype>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <algorithm>
#define INF (INT_MAX / 10)
#define clr(arr, val) memset(arr, val, sizeof(arr))
#define pb push_back
#define sz(a) ((int)(a).size())
using namespace std;
typedef set<int> si;
typedef vector<int> vi;
typedef map<int, int> mii;
typedef long long ll;
const double esp = 1e-5;
#define N 55
int pos[N], len, n, dp[N][N], vis[N][N];
/*
* 枚举第一次切割的位置,区间dp
* 记忆化搜索,写法不好
* 第l个切割位置到第r个切割位置的长度是pos[r + 1] - p[l - 1]
* 处理好边界就行了
*/
int getans(int l, int r)
{
if (dp[l][r] >= 0) {
return dp[l][r];
} else if (l == r) {
return dp[l][r] = pos[r + 1] - pos[l - 1];
} else if (l > r) {
return dp[l][r] = 0;
} else {
dp[l][r] = INF;
for (int k = l; k <= r; ++k) {
int tmp = getans(l, k - 1) + getans(k + 1, r)
+ pos[r + 1] - pos[l - 1];
dp[l][r] = min(dp[l][r], tmp);
}
return dp[l][r];
}
}
/*
* 使用vis标记计算过的
* 在边界的时候要注意当l大于r的时候,值应该是0,而且dp数组的
* 初始化值应该是一个足够大的值
*/
int getans2(int l, int r)
{
if (vis[l][r] == 1) {
return dp[l][r];
} else {
vis[l][r] = 1;
dp[l][r] = INF; //可以在使用之前初始化
for (int k = l; k <= r; ++k) {
int tmp = getans2(l, k - 1) + getans2(k + 1, r)
+ pos[r + 1] - pos[l - 1];
dp[l][r] = min(dp[l][r], tmp);
}
if (l > r) {
dp[l][r] = 0;
}
return dp[l][r];
}
}
/*
* 递推写法,也是先短后长
*/
int getans3(void)
{
//初始化为足够大的值
//当l大于r时初始化为0
//因为这个是边界条件,可以简化转移方程
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
dp[i][j] = (i > j) ? 0 : INF;
}
}
for (int i = 0; i < n; ++i) {
for (int j = 1; j + i <= n; ++j) {
for (int k = j; k <= j + i; ++k) {
int tmp = dp[j][k - 1] + dp[k + 1][j + i]
+ pos[j + i + 1] - pos[j - 1];
dp[j][j + i] = min(dp[j][j + i], tmp);
}
}
}
return dp[1][n];
}
int main(int argc, char *argv[])
{
while (scanf("%d", &len) != EOF) {
if (len == 0) {
break;
}
scanf("%d", &n);
//getans
//clr(dp, -1);
//getans2
//或者在之前总体初始化
//clr(dp, 0x3f);
clr(pos, 0);
clr(vis, 0);
pos[0] = 0;
pos[n + 1] = len;
for (int i = 1; i <= n; ++i) {
scanf("%d", &pos[i]);
}
//保证位置是升序的
sort(pos + 1, pos + 1 + n);
//printf("The minimum cutting is %d.\n", getans(1, n));
//printf("The minimum cutting is %d.\n", getans2(1, n));
printf("The minimum cutting is %d.\n", getans3());
}
return 0;
}
/*
Cutting Sticks
You have to cut a wood stick into pieces. The most affordable company,
The Analog Cutting Machinery, Inc. (ACM), charges money according to
the length of the stick being cut. Their procedure of work requires
that they only make one cut at a time.
It is easy to notice that different selections in the order of cutting
can led to different prices. For example, consider a stick of length
10 meters that has to be cut at 2, 4 and 7 meters from one end. There
are several choices. One can be cutting first at 2, then at 4, then at
7. This leads to a price of 10 + 8 + 6 = 24 because the first stick was
of 10 meters, the resulting of 8 and the last one of 6. Another choice
could be cutting at 4, then at 2, then at 7. This would lead to a price
of 10 + 4 + 6 = 20, which is a better price.
Your boss trusts your computer abilities to find out the minimum cost for
cutting a given stick.
Input
The input will consist of several input cases. The first line of each test
case will contain a positive number l that represents the length of the
stick to be cut. You can assume l < 1000. The next line will contain
the number n (n < 50) of cuts to be made.
The next line consists of n positive numbers ci ( 0 < ci < l) representing
the places where the cuts have to be done, given in strictly increasing order.
An input case with l = 0 will represent the end of the input.
Output
You have to print the cost of the optimal solution of the cutting problem,
that is the minimum cost of cutting the given stick. Format the output
as shown below.
Sample Input
100
3
25 50 75
10
4
4 5 7 8
0
Sample Output
The minimum cutting is 200.
The minimum cutting is 22.
*/