经典01背包问题。
解题思路比较常规。用辅助数组res存储容积为i时能装入物品的最大价值。对物品进行遍历,每次遍历中都逆序更新res,转移方程为res[j]=max(res[j-v[i]]+p[i],res[j])。最终res[v]即为要求的容积为v时所能装入物品的最大价值。
这道题设置了两问,解题上有细微差别。需要分开用两个辅助数组来存储结果。第一问求能装入物品的最大价值,没有要求刚好装满,所以直接把数组res的元素全部初始化为0即可。而第二问要求刚好装满时的最大价值。需要将res第一个元素初始化为0,代表容积为0的背包装满时最大价值为0;将其余元素全部初始化为一个很大的负数,要保证就算将所有物品的价值与这个数相加还会得到一个负数。这样,在按照与第一问同样的方法计算最大价值时,若不存在刚好装满的情况,res[v]就会为负数,因为没有办法从res[0]一直装物品装到res[v]。只有能从res[0]开始装,由于res[0]=0,才能规避掉初值的极大负值,得到一个正常的正值。所以最后判断res[0]即可,为正直接返回,为负返回0。

这里记录一下写的时候遇到的坑。
开始时将res数组初始化为大小为v的数组,提交时总有一些用例出问题。实际上这里辅助数组res[i]表示的是容积为i时能装入物品的最大价值,其范围应该是0,1,2,...,v,所以res初始化的大小应该是v+1,否则必定出错。

#include <iostream>
#include <vector>

using namespace std;

int main(){
    int n, v;
    cin >> n >> v;
    vector<int> arrv(n, 0);
    vector<int> arrp(n, 0);
    vector<int> res(v + 1, 0);
    vector<int> cres(v + 1, -99999);
    cres.at(0) = 0;
    for(int i = 0;i < n;i++){
        cin >> arrv.at(i) >> arrp.at(i);
    }
    for(int i = 0;i < n;i++){
        for(int j = v;j >= arrv.at(i);j--){
            res.at(j) = max(res.at(j - arrv.at(i)) + arrp.at(i), res.at(j));
            cres.at(j) = max(cres.at(j - arrv.at(i)) + arrp.at(i), cres.at(j));
        }
    }
    int max = res.at(v); 
    int comax = cres.at(v) > 0 ? cres.at(v) : 0;
    cout << max << endl << comax;
    return 0;
}



附一段递归代码,在第12个用例处超时,望大佬指点一下优化方法。

#include <iostream>
#include <vector>

using namespace std;

int n, V;
vector<int> price;
vector<int> volume;

int main(){
    cin >> n >> V;
    for(int i = 0;i < n;i++){
        int vt, vp;
        cin >> vt;
        cin >> vp;
        volume.push_back(vt);
        price.push_back(vp);
    }
    int put(int i, int v);
    int cput(int i, int v);
    cout << put(n - 1, V) << endl << (cput(0, V) > 0 ? cput(0, V) : 0);
}
int put(int i, int v){
    if(i < 0 || v == 0){
        return 0;
    }
    if(volume.at(i) > v){
        return put(i - 1, v);
    }
    else{
        return max(put(i - 1, v), put(i - 1, v - volume.at(i)) + price.at(i));
    }
}
int cput(int i, int v){
    if(i == n && v != 0){
        return -9999;
    }
    else if(v == 0){
        return 0;
    }
    else if(volume.at(i) > v){
        return cput(i + 1, v);
    }
    else{
        return max(cput(i + 1, v), cput(i + 1, v - volume.at(i)) + price.at(i));
    }
}