zoukankan      html  css  js  c++  java
  • 51Nod 1021~1023 石子合并 (逐步加强版) 【dp】

    51Nod 1021~1023  石子合并

    小结:

    这里给出三种做法。

    第一种:n^3  最基础的合并类dp, f[i,j]=min(f[i,j],f[i,k]+f[k,j]+w[i,j])

    这种代码不贴了,网上多的是。鄙人太弱(逃~)

    第二种: n^2  四边形不等式优化。。。

    主要是优化了 k 的枚举, k 从 s[i][j-1] 枚举到 s[i+1][j] 就行了。。。   ???证明(不会诶,以后再说)

    贴代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=2005;
     4 int n,f[N][N]={0},a[N][N]={0};
     5 int s[N][N];
     6 inline int read()
     7 {
     8     int x=0,f=1; char ch=getchar();
     9     while (!isdigit(ch)) f=(ch=='-')?-f:f,ch=getchar();
    10     while (isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    11     return x*f;
    12 }
    13 int main()
    14 {
    15     memset(f,1,sizeof(f));
    16     scanf("%d",&n);
    17     for (int i=0; i<n; i++)
    18     {
    19         scanf("%d",&a[i][i]);
    20         a[n+i][n+i]=a[i][i];
    21     }
    22     for (int i=0; i<n*2; i++)
    23     {
    24         s[i][i]=i;
    25         f[i][i]=0;
    26     }
    27     for (int i=0; i<n*2-1; i++)
    28       for (int j=i+1; j<n*2-1; j++)
    29         a[i][j]=a[i][j-1]+a[j][j];
    30     for (int l=1; l<n; l++)
    31     {
    32         for (int i=0; i+l<n*2-1; i++)
    33         {
    34             int j=i+l;
    35             for (int k=s[i][j-1]; k<=s[i+1][j]; k++)
    36             {
    37                 if (f[i][j]>a[i][j]+f[i][k]+f[k+1][j])
    38                 {
    39                     f[i][j]=a[i][j]+f[i][k]+f[k+1][j];
    40                     s[i][j]=k;
    41                 }
    42             }
    43         }
    44     }
    45     int ans=f[0][n-1];
    46     for (int i=1; i<n; i++)
    47       if (ans>f[i][i+n-1])
    48         ans=f[i][i+n-1];
    49     printf("%d
    ",ans);
    50     return 0;
    51 }
    View Code

    第三种(重点来了): GarsiaWachs算法 (是不是很上档次啊)

    大约 n log n (不要问我为什么,木鸡啊) 

    对于剩下的 k 堆石子,找出最小的堆 i, 并且满足 f[i-2]<=f[i],那么就优先合并 f[i-2] , f[i-1] 这两堆。

    然后把合并起来的一堆,从这往前找,找到第一个比它大的堆,插在它后面。以此循环,直到最后剩一堆。

    证明未知。。玄学做法。。。

    贴代码:

     1 #include<bits/stdc++.h>
     2 #define LL long long
     3 using namespace std;
     4 const int N=50005;
     5 int stone[N],n,t;
     6 LL ans;
     7 void combine(int k)
     8 {
     9     int tmp=stone[k]+stone[k-1];
    10     ans+=(LL)tmp;
    11     for (int i=k; i<t-1; i++)
    12       stone[i]=stone[i+1];
    13     t--;
    14     int j;
    15     for (j=k-1; j>0 && stone[j-1] < tmp; j--)
    16       stone[j]=stone[j-1];
    17     stone[j]=tmp;
    18     while (j>=2 && stone[j]>=stone[j-2])
    19     {
    20         int d=t-j;
    21         combine(j-1);
    22         j=t-d;
    23     }
    24 }
    25 int main()
    26 {
    27     scanf("%d",&n);
    28     for (int i=0; i<n; i++)
    29       scanf("%d",&stone[i]);
    30     t=1; ans=0;
    31     for (int i=1; i<n; i++)
    32     {
    33         stone[t++]=stone[i];
    34         while (t>=3 && stone[t-3] <=stone[t-1])
    35           combine(t-2);
    36     }
    37     while (t>1) combine(t-1);
    38     printf("%lld
    ",ans);
    39     return 0;
    40 }
    View Code

    (哦对了,注意开 long long,我一开始没开,后面爆了,数据乘起来蛮大的)

    加油加油加油!!!fighting fighting fighting!!!

  • 相关阅读:
    C++测试代码运行时间的模板
    Java学习第三天
    JAVA学习第二天
    Java第一天
    windows 查看端口号,关闭端口进程
    SAML 2.0简介(1)
    response 重定向
    Springboot+Mybatis+小程序
    Receiver class com.mchange.v2.c3p0.impl.NewProxyResultSet does not define or inherit an implementation of the resolved method 'abstract boolean isClosed()' of interface java.sql.ResultSet.
    Mysql常用语句
  • 原文地址:https://www.cnblogs.com/Frank-King/p/9313346.html
Copyright © 2011-2022 走看看