可行性判定(c++)

可行性判定

当前有 N 件物品和一个容积为 V 的背包。

已知第 i 件物品的体积是 ci​,每种物品有且仅有一件,每一件物品能够选择放或者不放入背包。

现在我们不考虑物品的价值,只关心是否能够取出若干个物品,恰好使这个背包被装满。

也就是说,现在我们需要选出若干件物品,使它们的体积之和 恰好为 V 。

dp 数组初始化

普通的 01 背包中要求放入物品的体积之和不超过 V,而现在我们需要使体积之和恰好为 V。

因为结果只需要输出 V 这个体积是否能被组出,因此我们可以将 dp 数组定义成bool类型。

  • 令 dp[i][j] 表示前  i 个物品中取出若干个物品体积之和为 j 的可行性,当可行的时候 dp[i][j] 等于 11,否则等于 00。
  • 在最开始背包里空空如也的时候,背包里物品的体积之和(没有物品)为 00,所以 00 这个状态在开始就是合法的。
  • 当要求选出物品体积之和恰好为 V 的条件下,唯一可行的转移路线是从 dp[0][0]→dp[N][V],即dp[0][0] 是唯一可行的起点。
  • 所以应当先将整个dp数组初始化为 00 ,再将 [0][0]dp[0][0] 修改为 11 。

核心代码

dp[0][0] = 1; // 初始化开始时唯一的合法状态
for (int i = 1; i <= N; i++) {
    for (int j = 0; j <= V; j++) {
        if (j < c[i]) { // 如果容积小于当前物品的体积
            dp[i][j] = dp[i - 1][j]; // 直接从上一层转移
        } else if (dp[i - 1][j] || dp[i - 1][j - c[i]]){
            // 如果前 i - 1 个物品已经能凑出体积之和为 j
            // 或者前 i - 1 个物品已经能凑出体积之和为 j - c[i] , 那个当前物品加入可以使体积之和变为 j
            dp[i][j] = 1; // 此时前 i 个物品能够凑出体积之和为 j
        }
    }
}

时间复杂度为 O(NV),空间复杂度为 O(NV)。

空间优化:

dp[0] = 1;
for (int i = 1; i <= N; i++) {
    for (int j = V; j >= c[i]; j--) {
        dp[j] |= dp[j - c[i]];
    }
}

完整代码:

#include <iostream>
using namespace std;

bool dp[110][1010];
int c[110];

int main() {
    int N, V;
    cin >> N >> V;
    for (int i = 1; i <= N; i++) {
        cin >> c[i];
    }
    dp[0][0] = 1;
    for(int i = 1; i <= N; i++){
        for(int j = 0; j <= V; j++){
            if (j < c[i]){
                dp[i][j] = dp[i - 1][j];
            } else if (dp[i - 1][j] || dp[i - 1][j - c[i]]){
                dp[i][j] = 1;
            }
        }
    }
    if (dp[N][V]){
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
    return 0;
}

  • 24
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值