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\n",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\n",ans);
  return 0;
}

 

转载于:https://www.cnblogs.com/2014nhc/p/6699710.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值