zoukankan      html  css  js  c++  java
  • BZOJ 2021: [Usaco2010 Jan]Cheese Towers

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2021

    参考博客:http://blog.csdn.net/popoqqq/article/details/46379189

    解:在看懂了原来的题解的基础上,以自己认为更好理解的方式修改了代码,虽然写的烦了一点,希望不要弄巧成拙。

    不用大奶酪的部分,我们直接用一个完全背包就可以解决,所以接下来我们只考虑奶酪塔中有大奶酪的情况。

    方法一:我们枚举用第i块大奶酪放在最上面(很明显,如果有用大奶酪的话,放在最上面肯定是最优的),然后将t变成t-h[i],再用所有奶酪4/5的高度,去做一次完全背包,比较好想,复杂度是O(n^2T),我没有写过这种方法所以不贴代码了。

    方法二:我们把奶酪分成大于等于k和不大于k的两部分,用g[j]来表示奶酪塔中有大奶酪的时候在j的高度下我们能获得的最大价值。重点就在于我们如何赋g的初值。

    h[i]代表的是第i块大奶酪(必须是大奶酪)g[h[i]]=max(g[h[i]],v[i]),剩余的g[j]都赋为-INF。然后直接用所有奶酪4/5的高度去套完全背包即

    g[j]=max(g[j],g[j-h[i]*4/5]+v[i]);复杂度是O(nT)

    这样做的理由在于如果我们要能把g[j]更新到一个正数,那么g[j-h[i]]必须不是-INF,即代表j-h[i]的最优价值所代表的奶酪,至少有一块是未被压缩,用完整高度的来更新它的(即那块垫底的大奶酪),否则,如果都是4/5的高度的话,因为初始-INF的存在,根本就达不到正数。开始的初始化就和方法一中枚举最上面的是哪块大奶酪的作用很像。

    方法三(其实不算。。):其实也可以不要这样初始化,贪心思想,利用了最终在一个奶酪塔中如果有两块即以上的大奶酪的话,放在最上面的那一块一定是高度更小的那一块,那么我们只要按照每块大奶酪的高度从小到大排序,然后,完全不要初始化,按照方法二的动归做就可以了。复杂度O(nlogn+nT);

    然后我用f数组套了一遍完全背包,来考虑奶酪塔中没有大奶酪的情况。

    下面是我用方法二的程序(我只是为了自己看的懂所以用了两个数组把它们分开,其实没什么必要。。):

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    struct ding{long long v,h;}a[110],b[110];
    int n,m,k,cnt1,cnt2;
    long long f[1010],g[1010],x,y,ans;
    int main()
    {
      scanf("%d%d%d",&n,&m,&k);
      for (int i=1;i<=n;i++) 
      {
          scanf("%lld%lld",&x,&y);
          if (y>=k) {a[++cnt1].h=y;a[cnt1].v=x;}
          else {b[++cnt2].h=y;b[cnt2].v=x;}
      }
      for (int i=0;i<=m;i++) f[i]=g[i]=-2100000000;
      for (int i=1;i<=cnt1;i++) g[a[i].h]=max(g[a[i].h],a[i].v);
      for (int i=1;i<=cnt1;i++)
      {
          int temp=(a[i].h/5)*4;
          for (int j=temp;j<=m;j++) g[j]=max(g[j-temp]+a[i].v,g[j]);
      }
      f[0]=0;
      for (int i=1;i<=cnt2;i++) 
      {
       int temp=b[i].h/5*4;
       for (int j=b[i].h;j<=m;j++) f[j]=max(f[j],f[j-b[i].h]+b[i].v);
       for (int j=temp;j<=m;j++) g[j]=max(g[j-temp]+b[i].v,g[j]);
      }
      for (int i=0;i<=m;i++) ans=max(max(ans,g[i]),f[i]);
      printf("%lld
    ",ans);
      return 0;
    }

    还有方法三的(少了初始化,多了一个排序):

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    struct ding{long long v,h;}a[110],b[110];
    int n,m,k,cnt1,cnt2;
    long long f[1010],g[1010],x,y,ans;
    bool cmp(const ding&c,const ding&d){return (c.h==d.h?c.v<d.v:c.h<d.h);}
    int main()
    {
      scanf("%d%d%d",&n,&m,&k);
      for (int i=1;i<=n;i++) 
      {
          scanf("%lld%lld",&x,&y);
          if (y>=k) {a[++cnt1].h=y;a[cnt1].v=x;}
          else {b[++cnt2].h=y;b[cnt2].v=x;}
      }
      for (int i=0;i<=m;i++) f[i]=g[i]=-2100000000;
      sort(a+1,a+1+cnt1,cmp); sort(b+1,b+1+cnt2,cmp);
      for (int i=1;i<=cnt1;i++)
      {
          int temp=(a[i].h/5)*4;
          g[a[i].h]=max(g[a[i].h],a[i].v);
          for (int j=temp;j<=m;j++) g[j]=max(g[j-temp]+a[i].v,g[j]);
      }
      f[0]=0;
      for (int i=1;i<=cnt2;i++) 
      {
       int temp=b[i].h/5*4;
       for (int j=b[i].h;j<=m;j++) f[j]=max(f[j],f[j-b[i].h]+b[i].v);
       for (int j=temp;j<=m;j++) g[j]=max(g[j-temp]+b[i].v,g[j]);
      }
      for (int i=0;i<=m;i++) ans=max(max(ans,g[i]),f[i]);
      printf("%lld
    ",ans);
      return 0;
    }
  • 相关阅读:
    vue自定义指令
    ZOJ Problem Set–2104 Let the Balloon Rise
    ZOJ Problem Set 3202 Secondprice Auction
    ZOJ Problem Set–1879 Jolly Jumpers
    ZOJ Problem Set–2405 Specialized FourDigit Numbers
    ZOJ Problem Set–1874 Primary Arithmetic
    ZOJ Problem Set–1970 All in All
    ZOJ Problem Set–1828 Fibonacci Numbers
    要怎么样调整状态呢
    ZOJ Problem Set–1951 Goldbach's Conjecture
  • 原文地址:https://www.cnblogs.com/2014nhc/p/6699710.html
Copyright © 2011-2022 走看看