原题链接
题目大意
给你总时间和草药的个数,每个草药有价值和采取需要的时间,求出在有限的时间内,你可以采到最多多少价值的草药
S
a
m
p
l
e
\mathbf{Sample}
Sample
I
n
p
u
t
\mathbf{Input}
Input
70 3
71 100//时间和价值
69 1
1 2
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output
3
H
i
n
t
&
E
x
p
l
a
i
n
\mathbf{Hint\&Explain}
Hint&Explain
取第二个和第三个草药,时间为69+1=70
,价值为2+1=3
。
解题思路
这一题可以分为顺推和逆推两种做法。
①顺推
就是用
d
p
dp
dp二维数组,容量从
1
∼
m
1\sim m
1∼m开始循环。
设
d
p
i
,
j
dp_{i,j}
dpi,j为在容量
j
j
j时取第
1
∼
i
1\sim i
1∼i个草药可以得到的最大价值,
w
i
w_i
wi是取第
i
i
i个草药所需的时间,
c
i
c_i
ci为第
i
i
i个草药的价值,则:
d
p
i
,
j
=
{
0
i
=
0
d
p
i
−
1
,
j
1
≤
j
<
w
i
m
a
x
(
d
p
i
−
1
,
j
,
d
p
i
−
1
,
j
−
w
i
+
c
i
)
1
≤
i
≤
n
,
w
i
≤
j
≤
m
dp_{i,j}=\begin{cases} 0&i=0 \\dp_{i-1,j}&1\le j< w_i \\max(dp_{i-1,j},dp_{i-1,j-w_i}+c_i)&1\le i\le n,w_i\le j\le m \end{cases}
dpi,j=⎩⎪⎨⎪⎧0dpi−1,jmax(dpi−1,j,dpi−1,j−wi+ci)i=01≤j<wi1≤i≤n,wi≤j≤m
答案就是:
d
p
n
,
m
dp_{n,m}
dpn,m
代码:
#include<iostream>
#include<cstring>
using namespace std;
int n,m;
int w[110],c[110];
int dp[110][1010];
int main()
{
memset(dp,0,sizeof(dp));
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-1][j-w[i]]+c[i]);
else
dp[i][j]=dp[i-1][j];
}
}
cout<<dp[n][m]<<endl;
return 0;
}
②逆推
就是用
d
p
dp
dp一维数组,容量从
m
∼
1
m\sim 1
m∼1循环
设
d
p
j
dp_{j}
dpj为在容量
j
j
j时可以得到的最大价值,其他同顺推,则:
d
p
j
=
{
0
j
=
0
d
p
j
−
w
i
+
c
i
1
≤
i
≤
n
,
w
i
≤
j
≤
m
dp_j=\begin{cases} 0&j=0 \\dp_{j-w_i}+c_i&1\le i\le n,w_i\le j\le m \end{cases}
dpj={0dpj−wi+cij=01≤i≤n,wi≤j≤m
答案就是
d
p
m
dp_m
dpm
代码在下面
上代码
此为逆推代码
#include<iostream>
using namespace std;
int n,m;
int w[110],c[110];
int dp[1010];
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=m; j>=w[i]; j--)
{
dp[j]=std::max(dp[j],dp[j-w[i]]+c[i]);
}
}
cout<<dp[m]<<endl;
return 0;
}
完美切题 ∼ \sim ∼