zoukankan      html  css  js  c++  java
  • nyoj737区间dp(石子合并)

    石子合并(一)

    时间限制:1000 ms  |  内存限制:65535 KB
    难度:3
     
    描述
        有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。
     
    输入
    有多组测试数据,输入到文件结束。
    每组测试数据第一行有一个整数n,表示有n堆石子。
    接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开
    输出
    输出总代价的最小值,占单独的一行
    样例输入
    3
    1 2 3
    7
    13 7 8 16 21 4 18
    样例输出
    9
    239

    区间dp,无论有多少堆石子,最后总要是分成了两堆,然后合成这两堆,我们要求出最小消耗值。
    dp[start][end]表示取走start到end位置的石子的最小消耗值,
    我们假设子问题答案已经求出,则有:dp[i][j]=MIN{dp[i][k]+dp[k+1][j]+SUM(i,j)|i<=k<j}
    不难发现要想求出长度为len的区间的最小值,我们需要长度为(1---len-1)之间的最小值作为支撑递推继续下去的源泉,
    所有想到,从长度为1开始递推直至推到长度为n也就是answer!
    显然是一个O(N^3)复杂度的DP,有四边形优化为O(N^2),目前不会,以后补。

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 0x3f3f3f3f
    int a[205],dp[205][205];
    int sum[205][205];
    int SUM(int s,int e)
    {
    if(sum[s][e]!=-1) return sum[s][e];
    int sumn=0,i;
    for(i=s;i<=e;++i) sumn+=a[i];
    return sum[s][e]=sumn;
    }
    int main()
    {
    int n,m,i,j,k;
    while(cin>>n){memset(dp,inf,sizeof(dp));memset(sum,-1,sizeof(sum));
    for(i=1;i<=n;++i) scanf("%d",&a[i]),dp[i][i]=0;
    for(k=2;k<=n;++k)                              //控制区间长度
    for(i=1;i+k-1<=n;++i){                          //i表示起点,由于长度的限制i不可取任意值
    int minn=inf;
    for(j=i;j<=i+k-1;++j) if(dp[i][j]+dp[j+1][i+k-1]<minn) minn=dp[i][j]+dp[j+1][i+k-1];     //j表示从此点分开,minn表示后合并左右两堆最小的值
    dp[i][i+k-1]=minn+SUM(i,i+k-1);
    }
    cout<<dp[1][n]<<endl;
    }
    return 0;
    }

  • 相关阅读:
    (转)了解JNDI
    java.lang.ClassNotFoundException: com.mysql.jdbc.Driver问题
    占个座
    关于 inode 与 iblock 的知识
    机器学习性能度量指标:ROC曲线、查准率、查全率、F1
    编译出现的问题解决
    二分查找(Binary Search)
    ST算法 Sliding Window algorithm template
    数据结构_算法
    知识点积累
  • 原文地址:https://www.cnblogs.com/zzqc/p/6757083.html
Copyright © 2011-2022 走看看