整理书本

问题 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;
}
View Code
原文地址:https://www.cnblogs.com/great-xxr/p/5679730.html