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;
    }
  • 相关阅读:
    WPS企业版序列号
    局域网远程
    win10 新增、删除、重命名文件需要刷新才更新的问题
    nginx配置文件参数详解
    TCP/IP协议明明白白
    iperf3
    华为交换机流量统计
    delphi 数据库技术沉浮录--谨献给成为历史的BDE
    在ubuntu 上使用wine 运行Delphi win32 应用
    kbmmw 中实现客户端自动更新
  • 原文地址:https://www.cnblogs.com/2014nhc/p/6699710.html
Copyright © 2011-2022 走看看