原题链接
题目大意
设有
n
n
n种物品,每种物品有一个重量及一个价值,每种物品的数量是无限的,求出在一定的重量限制下你可以取到总和最多多少价值的物品。
S
a
m
p
l
e
\mathbf{Sample}
Sample
I
n
p
u
t
\mathbf{Input}
Input
12 4
2 1
3 3
4 5
7 9
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output
15
H
i
n
t
&
E
x
p
l
a
i
n
\mathbf{Hint\&Explain}
Hint&Explain
拿
3
3
3个第
3
3
3种物品,重量为4*3=12
,价值为5*3=15
。
解题思路
本题为完全背包,从
1
∼
m
1\sim m
1∼m循环遍历时间,如果够拿某一个东西就比较一下拿与不拿的价值即可。
本题有两种做法,一种是用二维数组,一种是压缩空间一维数组。
①二维数组
从
1
∼
m
1\sim m
1∼m循环容量,如果容量不够当前物品,就直接继承上一个状态,如果够,就变成取和不取的最大值,即:
设
d
p
i
,
j
dp_{i,j}
dpi,j为当容量为
j
j
j时取前
i
i
i个物品所得到的最大价值,
w
i
w_{i}
wi为
i
i
i物品的重量,
c
i
c_i
ci为
i
i
i物品的价值。
d
p
i
,
j
=
{
d
p
i
−
1
,
j
1
≤
i
≤
n
,
0
≤
j
<
w
i
m
a
x
(
d
p
i
−
1
,
j
,
d
p
i
,
j
−
w
i
+
c
i
)
1
≤
i
≤
n
,
w
i
≤
j
≤
m
dp_{i,j}=\begin{cases} dp_{i-1,j}&1\le i\le n,0\le j<w_i \\max(dp_{i-1,j},dp_{i,j-w_i}+c_i)&1\le i\le n,w_i\le j\le m \end{cases}
dpi,j={dpi−1,jmax(dpi−1,j,dpi,j−wi+ci)1≤i≤n,0≤j<wi1≤i≤n,wi≤j≤m
答案就是:
d
p
n
,
m
dp_{n,m}
dpn,m
核心代码:
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(j>=w[i])
dp[i][j]=std::max(dp[i-1][j],dp[i][j-w[i]]+c[i]);
else
dp[i][j]=dp[i-1][j];
}
}
完整代码如下:
#include<iostream>
using namespace std;
int n,m;
int w[40],c[40];
int dp[40][210];
int main()
{
cin>>m>>n;
for(int i=1; i<=n; i++) cin>>w[i]>>c[i];
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(j>=w[i])
dp[i][j]=std::max(dp[i-1][j],dp[i][j-w[i]]+c[i]);
else
dp[i][j]=dp[i-1][j];
}
}
cout<<dp[n][m]<<endl;
return 0;
}
②一维数组
做法和二维数组的做法大同小异,只是在状态转移方程上把第一维的
i
i
i去掉了,即:
d
p
j
=
{
d
p
j
1
≤
i
≤
n
,
0
≤
j
<
w
i
m
a
x
(
d
p
j
,
d
p
j
−
w
i
+
c
i
)
1
≤
i
≤
n
,
w
i
≤
j
≤
m
dp_{j}=\begin{cases} dp_{j}&1\le i\le n,0\le j<w_i \\max(dp_{j},dp_{j-w_i}+c_i)&1\le i\le n,w_i\le j\le m \end{cases}
dpj={dpjmax(dpj,dpj−wi+ci)1≤i≤n,0≤j<wi1≤i≤n,wi≤j≤m
答案就是:
d
p
m
dp_m
dpm
核心代码:
for(int i=1; i<=n; i++)
{
for(int j=w[i]; j<=m; j++)
{
dp[j]=std::max(dp[j],dp[j-w[i]]+c[i]);
}
}
上代码
#include<iostream>
using namespace std;
int n,m;
int w[40],c[40];
int dp[210];
int main()
{
cin>>m>>n;
for(int i=1; i<=n; i++) cin>>w[i]>>c[i];
for(int i=1; i<=n; i++)
{
for(int j=w[i]; j<=m; j++)
{
dp[j]=std::max(dp[j],dp[j-w[i]]+c[i]);
}
}
cout<<dp[m]<<endl;
return 0;
}
完美切题 ∼ \sim ∼