NYOJ 737 石子合并(一)(区间DP、平行四边形优化、GarsiaWachs算法)

来源:互联网 发布:林珊珊几个淘宝店铺 编辑:程序博客网 时间:2024/05/29 21:33

石子合并(一)

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

三种方法,对应时间效率分别为O(n^3)、O(n^2)、O(nlogn)


普通的区间DP,很容易想到,时间效率为O(n^3)

//O(n^3)#include <stdio.h>int dp[203][203],sum[203];int min(int a,int b){return a>b?b:a;}int main(){int n,a;while(scanf("%d",&n)!=EOF){for(int i=1;i<=n;i++){scanf("%d",&a);sum[i]=sum[i-1]+a;dp[i][i]=0;}// 区间DPfor(int count=2;count<=n;count++){   // 遍历合并count=2堆、3堆、...n堆的情况for(int start=1;start<=n-count+1;start++){   // start表示每个区间的始点int end=start+count-1;  // end表示对应的该区间的终点dp[start][end]=0x3f3f3f3f;for(int mid=start;mid<=end;mid++){dp[start][end]=min(dp[start][end],dp[start][mid]+dp[mid+1][end]+sum[end]-sum[start-1]);}}}printf("%d\n",dp[1][n]);}return 0;}

平行四边形优化后时间效率为O(n^2)

附四边形优化讲解:http://www.cnblogs.com/zxndgv/archive/2011/08/02/2125242.html

//O(n^2)#include <stdio.h>#include <string.h>int dp[203][203], sum[203], s[203][203];int main(){int n, i, j, k, len, x;while(scanf("%d",&n)!=EOF){sum[0]=0;for(i=1;i<=n;i++){scanf("%d",&x);sum[i]=sum[i-1]+x;dp[i][i]=0;s[i][i]=i;}for(len=2;len<=n;len++){for(i=1;i<=n-len+1;i++){j=i+len-1;dp[i][j] = 0x3f3f3f3f;for(k=s[i][j-1];k<=s[i+1][j];k++){if(dp[i][j]>dp[i][k-1]+dp[k][j]+sum[j]-sum[i-1]){dp[i][j]=dp[i][k-1]+dp[k][j]+sum[j]-sum[i-1];s[i][j]=k;}}}}printf("%d\n",dp[1][n]);}return 0;}

石子合并的GarsiaWachs算法,时间效率可达O(nlogn)

附石子合并的GarsiaWachs算法讲解:http://blog.csdn.net/acdreamers/article/details/18043897

//O(nlogn)#include <cstdio>const int N=210;int n,t,stone[N],ans;void combine(int k){    int tmp=stone[k]+stone[k-1];    ans+=tmp;    for(int i=k; i<t-1; i++)        stone[i]=stone[i+1];    t--;    int j;    for(j=k-1; j>0 && stone[j-1]<tmp; j--)        stone[j] = stone[j-1];    stone[j] = tmp;    while(j >= 2 && stone[j] >= stone[j-2])    {        int d = t - j;        combine(j-1);        j = t-d;    }}int main(){    while(~scanf("%d",&n))    {        for(int i=0; i<n; i++) scanf("%d",&stone[i]);        t=1,ans=0;        for(int i=1;i<n;i++)        {            stone[t++]=stone[i];            while(t >=3 && stone[t-3]<=stone[t-1])                combine(t-2);        }        while(t > 1) combine(t-1);        printf("%d\n" , ans);    }    return 0;}        


0 0
原创粉丝点击