题意:
题目的意思就是,有一根木根,长度为 l ,要给它n刀.分别在c1,c2,c3…cn的位置切.
每一刀的消费是当前这段木棍的长度.
比如长度10 , 要在2,4,7三个位置切.假设顺序是 4, 2 ,7.
切4这个位置的时候,木棍长度10 ,消耗10,然后切2这个位置的时候,它所在的地方木棍长度是4 ,消耗4,切7时消耗6.总共10 + 4 +6 = 20.
这种切法也是最省的,如果2.4.7要10 + 8 +6 =24.
题目就是要求最少消耗.
思路:区间DP
定义状态:D[ i ][ j ]:切第 i 到第 j 个切点的最小花费。 此时的花费怎么求?
比如第一次切,i = 1, j = n; 花费就是 j 的上界 减去 i 的下界,即A[j+1] - A[i-1]。这里两端节点左右是有延展的。所以我们加入两个虚拟切点,A[0] = 0,A[n+1] = s(初始木棍长度)。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 1<<30;
const int N = 50+5;
int s,n,A[N]; // 切割坐标
int d[N][N];
int f(int i, int j){
int& ans = d[i][j];
if(ans > 0) return ans;
if(i > j) return ans = 0;
ans = INF;
for(int k = i; k <= j; ++k){
int up = A[j+1];
int down = A[i-1];
ans = min(ans, f(i,k-1)+f(k+1,j)+up-down);
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d",&s) == 1&&s){
memset(d,0,sizeof(d));
int n; scanf("%d",&n);
for(int i = 1; i <= n; ++i){
scanf("%d",&A[i]);
}
A[0] = 0; A[n+1] = s;
//递推初始化
for(int i = 1; i <= n; ++i){
int up = A[i+1], down = A[i-1];
d[i][i] = up - down;
}
/*
for(int len = 1; len < n; ++len){ // 区间长度
for(int i = 1; i+len <= n; ++i){ // 区间起点
int j = i + len;
int up = A[j+1], down = A[i-1];
d[i][j] = INF;
for(int k = i; k <= j; ++k){ // 枚举切割点
d[i][j] = min(d[i][j], d[i][k-1] + d[k+1][j] + up-down);
}
}
}
int ans = d[1][n];
*/
int ans = f(1,n);
printf("The minimum cutting is %d.\n",ans);
}
return 0;
}
递推30ms,记忆化搜索150ms,差距比我想象中大一点。