题目链接: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; }