多重背包
1.这个就是在0 1 背包的条件下 加上每个物品能被多次取到!
优化方式 数学知识来优化 :并不是二进制!
首先我们要搞明白多重背包问题,总点就是状态的更新,是以一个什么方式递推过去的,举个例子如果是L[i]个物品,如果是从1-L[i]枚举过去我们不难知道其实,我们这样计算的其实是有一共ΣL[i]1 件物品了,所以并不是我们所需要的情况所以我们需要的是更新1,2,3,4,5,6,7...L[i],这些情况那就要保证我们枚举的时候是刚好可以覆盖掉这些情况 ,需要一定的数学知识:
for(i=1;i<=n;i++) { int res=l[i]; for(k=1;k<=res;res-=k,k*=2) for(j=m;j>=k*v[i];j--) f[j]=max(f[j],f[j-v[i]*k]+w[i]*k); for(j=m;j>=res*v[i];j--) f[j]=max(f[j],f[j-v[i]*res]+w[i]*res); }
这一个 每个数都可以被 1 2 4 8 ....构成 最多再加上一个余数 用一个递增的序列 !!
其中这里面有一个很有趣的点 如你要有三个物品的情况 是 1+2 得到的 因为你在第一次更新过的状态下继续更新同样的 2 就是由2 得到!而3是通过数组组合得到的因为已经考虑了取一个的,那么在取一个的情况下取考虑取两个 那就是三个 ,这个很容易去证明 !!这种写法的正确性 关键就是有点像暴力如何把全部都枚举到!!! 这一点非常非常关键 只要一把他全部跑一遍得到的就算最优解!!
然后还有一个队列优化目前还没研究透彻先贴一份代码来
//太妙了!!很好琢磨琢磨
// % % % %
#include <bits/stdc++.h>
using namespace std;
int n,m;
int v,l,w,f[10001],c[10001][2];//c[] [] 代表的是一个队列!
int main()
{
scanf("%d%d",&n,&m);
int i,j,k;
int x;
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&v,&w,&l);
for(j=0;j<v;j++)
{
int front=1,rear=0;
for( k=j,x=1 ; k<=m ; x++,k+=v)
{
int p=f[k]-x*w,q=x+l;
for(;front<=rear&&c[rear][0]<=p;rear--);
c[++rear][0]=p;c[rear][1]=q;
f[k]=c[front][0]+x*w;
for(;front<=rear&&c[front][1]==x;++front);
}
}
}
cout<<f[m];
}
这个自己细品!!
就基本上就是0 1 背包加上优化!
还有一个特别好的题 思路++ 思路up up !

这个是一个完全背包加上一个分组背包!
不妨设一个 f ,一个 g
g 是一个完全背包存找x 元所需的最少硬币
而f 是一个多重背包弄付 x 元所需的最少硬币
这样 f [ x ] +g [ x-m ] 元 就是刚好为m的 不断枚举去找最小
而且这道题的范围数组要开的大小很难确定值得取研究

这个东西很有意思!!

浙公网安备 33010602011771号