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;
}

 

posted @ 2024-05-23 14:39  五月江城  阅读(29)  评论(0编辑  收藏  举报