背包dp复习
__vector__ · · 个人记录
P1048 [NOIP2005 普及组] 采药
难度:\color{orange}\text{普及-}
\color{green}\text{AC算法:01背包}
题目分析:
题目转化:有
可以设一个状态
dpm[i][j]=max(dpm[i-1][j],dpm[i-1][j-ti[i]]+w[i]);
\color{green}\text{AC算法:完全背包}
题目分析:
本题与01背包类似,只是变成了每种有无限个。但是此时状态转移方程却还是原来那个:
放上\color{green}\text{AC} 代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define reg register
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int maxn=1e4+5;
const int maxdp=1e7+5;
int t,m;
int ti[maxn];
int w[maxn];
ll dpm[maxdp];
inline void dp()
{
for(reg int i=1;i<=m;i++)
{
for(int j=ti[i];j<=t;j++)
{
dpm[j]=max(dpm[j],dpm[j-ti[i]]+w[i]);
}
}
}
signed main()
{
t=read();
m=read();
for(reg int i=1;i<=m;i++)
{
ti[i]=read();
w[i]=read();
}
dp();
printf("%lld",dpm[t]);
return 0;
}
P1776 宝物筛
难度:\color{green}\text{ 普及+/提高}
\color{green}\text{AC算法:多重背包}
题目分析:
题目转化:
给一个大小为
可以发现,它与01背包不同之处在于它一个物品有多个。这样就可以把第
其中
但是这样复杂度就太高了
可以使用二进制拆分。将其拆分成大小分别为
\color{green}\text{AC代码:}
#include <bits/stdc++.h>
using namespace std;
#define reg register
int n,W;//背包大小为W
const int maxn=1e5+5;
const int maxw=4e4+5;
int v[maxn];//价值
int w[maxn];//重量
int m[maxn];//m件
int f[maxn];
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
inline void dp()
{
for(reg int i=1;i<=n;i++)
{
int mi=m[i];
int wi=w[i],vi=v[i];
int pkg=1;
while(mi>pkg)
{
mi-=pkg;
wi=w[i]*pkg;
vi=v[i]*pkg;
for(reg int j=W;j>=wi;j--)
{
f[j]=max(f[j],f[j-wi]+vi);
}
pkg*=2;
}
wi=w[i]*mi;
vi=v[i]*mi;
for(reg int j=W;j>=wi;j--)
{
f[j]=max(f[j],f[j-wi]+vi);
}
}
}
int main()
{
n=read();
W=read();
for(reg int i=1;i<=n;i++)
{
v[i]=read();
w[i]=read();
m[i]=read();
}
dp();
printf("%d",f[W]);
return 0;
}