问题 B: 整理书本(book)
时间限制: 1 Sec 内存限制: 64 MB提交: 24 解决: 10
[提交][状态][讨论版]
题目描述
小A想把他满屋子的书整理一下。书本分成若干堆。每一堆的书本都有质量w和价值V。小A 的任务是将所有书合成一堆。因为小A认为合并i,j两堆的书所需要的力为w[i]-v[i]+w[j]-v[j]。合并后的书堆的质量和价值均为合并前两 堆书的质量和价值的总和。也就是说,合并i,j两堆的书后,W=w[i]+w[j],V=v[i]+v[j]。合并只能在相邻两堆书本间进行。书本合并前 后,位置不变。如果将1,2,3中的l,2进行合并,那么合并结果为3,3,再将3,3合并为6(1,2,3,6指质量)。请你帮他计算最少需要花费多少 力气。
输入
第1行是一个整数n(2≤n≤400)。
第2~n+l行每行两个整数w和v(0<v<w<=1000)
输出
仅1行,只有一个整数,表示花费的最少力气。
样例输入
3
6 5
9 7
11 2
样例输出
15
提示
样例说明:先将前两堆合并,再将合并后的书堆与剩余的一堆合并。
#include<stdio.h> #define X 400 //定义最大测资为400 int a[X]; int f[X][X]; //f[i][j] (i<=j) 存放i~j合并为一堆的最小力气花费,若i>j,则为-1 long int m=0; //m为总合并重量 int sum(int start,int end) //计算从起点到终点的累加和 { int i,s=0; for(i=start;i<=end;i++) s+=a[i]; return s; } int fun(int s,int e) //求从s开始到e结束合并为一堆的最小力气花费 { int k,min=99999999; //min 存放最小值,初始其为一个很大的数,可以改为int类型的最大数 if(s==e) //起点和终点为一个点 return 0; if(s==e-1) //起点和终点相邻 { f[s][e]=sum(s,e); //写入f数组 return f[s][e]; } if(f[s][e]!=-1) //不等于-1表示之前已经计算过!所以直接返回 return f[s][e]; for(k=s;k<e;k++) //以前没有计算过,那么递归计算,找最小值! { if(min>fun(s,k)+fun(k+1,e)) min=fun(s,k)+fun(k+1,e); } min=min+sum(s,e); f[s][e]=min; return min; } int main() { int n; int w,v=0,i,j; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d%d",&w,&v); a[i]=w-v; } for(i=0;i<n;i++) //f数组所有元素都赋值-1 for(j=1;j<=n;j++) f[i][j]=-1; for(i=0;i<n;i++) //对角线元素为0 f[i][i]=0; m=fun(0,n-1); //求最小力气! printf("%ld ",m); return 0; }