CSP历年复赛题-P1048 [NOIP2005 普及组] 采药
原题链接:https://www.luogu.com.cn/problem/P1048
题意解读:在有限的时间内,采集到最大价值的草药,实际上是01背包问题,这里的总时间就是背包的体积。
解题思路:
设v[]表示每株草药的时间, w[]表示每株草药的价值,
dp[i][j]表示采前i株草药在时间j内可得到的最大价值,
对于第i株草药,采或不采,取max,可得递推公式:dp[i][j] = max(dp[i][j], dp[i-1][j-v[i]] + w[i]);
注意i取值1~m,j取值0~t,要保证j-v[i]>=0才可采第i株
100分代码(二维):
#include <bits/stdc++.h>
using namespace std;
const int N = 105, M = 1005;
int t, m;
int v[N], w[N]; //v:时间 w:价值
int dp[N][M]; //dp[i][j]表示采前i株草药在时间j内可得到的最大价值
int main()
{
cin >> t >> m;
for(int i = 1; i <= m; i++) cin >> v[i] >> w[i];
for(int i = 1; i <= m; i++)
{
for(int j = 0; j <= t; j++)
{
dp[i][j] = dp[i-1][j];
if(j >= v[i])
dp[i][j] = max(dp[i][j], dp[i-1][j-v[i]] + w[i]);
}
}
cout << dp[m][t];
return 0;
}
由于i只跟i-1有关,可以用一维数组进行优化
又因为j通过更小的j-v[i]推出,如果在一维的情况下,先更新小的dp[j],会导致后面计算依赖的dp[j]发生变化,所有要先更新大的j,也就是j的遍历要从大到小,另外可以把j >= v[i]直接提到for条件中
100分代码(一维):
#include <bits/stdc++.h>
using namespace std;
const int N = 105, M = 1005;
int t, m;
int v[N], w[N]; //v:时间 w:价值
int dp[M]; //dp[j]表示在时间j内可得到的最大价值
int main()
{
cin >> t >> m;
for(int i = 1; i <= m; i++) cin >> v[i] >> w[i];
for(int i = 1; i <= m; i++)
{
for(int j = t; j >= v[i]; j--)
{
dp[j] = max(dp[j], dp[j-v[i]] + w[i]);
}
}
cout << dp[t];
return 0;
}