1625: 割木棍
Time Limit: 1 Sec Memory Limit: 128 MB[ Submit][ Status][ Web Board]
Description
给你一根长为 l 的木棍,有 n 标记,每个标记都需要割断,每割一个木棍所需的花费是当前木棍的长度。求最小的花费。
Input
第一行输入 l ,(l=0时结束)l<=1000
第二行输入一个n ,n<=50
输入n 个数a[i],每个数表示原木棍 a[i] 长度处 有一个标记 0<a[i]<l
Output
输出最小的花费
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.
【分析】
很明显的dp...不过我怀疑这个数据范围dfs剪枝也可以过....看怎么优化了
这里讲dp...f[i][j]表示从编号i~j的点全部割掉所需要的最小花费,然后类似dijkstra算法...去补齐f[i][j],显然应该从小区间开始,也就是j-i=2开始 然后j-i=3,j-i=4.....直到最后答案,这里可以加个小优化,可以让程序更加简单,就是多加两个点,一个点是0,一个点是l
这样的话f[0][n+1]就是答案
f[i][j]的状态转移也比较容易,f[i][j]=f[i][k]+f[k][j]+a[j]-a[i]; (i<k<j);
(不过后来考虑了一下,发现,其实不需要每次清空状态数组f,每次新的运算只需要f[i][i+1]=0就可以了~算是对这道题目一个更加小的一个优化吧)
【代码】
#include <stdio.h>
#include <string.h>
int a[1000];
int f[100][100];
int main()
{
int l;
while (~scanf("%d",&l)&& l)
{
memset(f,0,sizeof(f));
int n;scanf("%d",&n);
a[0]=0;a[n+1]=l;
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int len=2;len<n+2;len++)
{
for (int i=0;i<=n-len+1;i++)
{
f[i][i+len]=f[i][i+1]+f[i+1][i+len]+a[i+len]-a[i];
for (int j=i+2;j<i+len;j++)
if ((f[i][j]+f[j][i+len]+a[i+len]-a[i])<f[i][i+len])
f[i][i+len]=f[i][j]+f[j][i+len]+a[i+len]-a[i];
}
}
printf("The minimum cutting is %d.\n",f[0][n+1]);
}
return 0;
}