【动态规划】背包问题求方案数

☆☆☆ 求方案数问题

前言

☆情况一:从前 i 个物品中选,且总体积不超过 j 的总方案数,初始化是 f[0][i] = 1, 0 <= i <= m,其余是0

01 背包

例子:给你一堆物品,每个物品有一定的体积,每个物品只能选一个,求总体积不超过 m的方案数

输入

4 5
2 2 3 7

输出

7

二维代码

#include <bits/stdc++.h>
using namespace std;

const int N = 100;

int f[N][N];
int n, m;

int main() {
    
    cin >> n >> m;
    
    /*初始化 当 0 个物品,体积不超过 i 的方案数,
     即不选为1种方案 , 即 i 从 0 - m 初始化
     	1 1 2 2 2 2   //不选时从上一状态转移过来,选时则有 叠加 1 ,表示当前选与不选两种方案
		1 1 3 3 4 4 
		1 1 3 4 5 7 
		1 1 3 4 5 7 
    */
    for (int i = 0; i <= m; i ++ ) f[0][i] = 1;
    
    for (int i = 1; i <= n; i ++ ) {
        int v;
        cin >> v;
        for (int j = 0; j <= m; j ++ ) {
            f[i][j] = f[i-1][j]; //不选的方案数
            if (j >= v) f[i][j] += f[i-1][j-v];  //加上满足可以选的方案数 
        }
    }
    
    cout << f[n][m];
    
    return 0;
}

状态压缩

#include <bits/stdc++.h>
using namespace std;

const int N = 100;

int f[N];
int n, m;

int main() {
    
    cin >> n >> m;
    
    //初始化 当 0 个物品,体积不超过 i 的方案数, 即不选为1种方案 , 即 i 从 0 - m 初始化
    for (int i = 0; i <= m; i ++ ) f[i] = 1;
    
    for (int i = 1; i <= n; i ++ ) {
        int v;
        cin >> v;
        for (int j = m; j >= v; j -- ) {
            f[j] += f[j - v];
        }
    }
    
    cout << f[m];
    
    return 0;
}

完全背包

例子:给你一堆物品,每个物品有一定的体积,每个物品可以选无数多个,求总体积不超过 m 的方案数

输入

3 5
2 3 7

输出

5

二维代码

#include <bits/stdc++.h>
using namespace std;

const int N = 100;

int n, m;
int f[N][N];

int main() {
    
    cin >> n >> m;
    
    /*
		同理,需要注意的时,本来加上的是当前物品不选,或者选一个,两个。。。的方案数
		在经过状态压缩后,只需要加上 f[i][j - v]即可
	*/
    for (int i = 0; i <= m; i ++ ) f[0][i] = 1;
    
    for (int i = 1; i <= n; i ++ ) {
        int v;
        cin >> v;
        for (int j = 0; j <= m; j ++ ) {
            f[i][j] = f[i-1][j];
            if (j >= v) f[i][j] += f[i][j-v];
        }
    }
    
    cout << f[n][m];
    
    return 0;
}

状态压缩

#include <bits/stdc++.h>
using namespace std;

const int N = 100;

int n, m;
int f[N];

int main() {
    
    cin >> n >> m;
    /*
    注意这里的状态转移,不懂可以看上面给出的连接,在背包最大最小值问题里面有讲解
    */
    for (int i = 0; i <= m; i ++ ) f[i] = 1;
    
    for (int i = 1; i <= n; i ++ ) {
        int v;
        cin >> v;
        for (int j = v; j <= m; j ++ ) {
            f[j] += f[j - v];
        }
    }
    
    cout << f[m];
    
    return 0;
}

☆情况二:从前 i 个物品中选,且总体积恰好是 j 的总方案数,初始化是 f[0][0] = 1, 其余是 0

:在此情况下,当的 f[i][j] = 1 时,表示只能恰好由自己组成一种方案,不能选其他物品

01背包

例子:给你一堆物品,每个物品有一定的体积,每个物品只能选一个,求总体积恰好是 m 的方案数

输入

4 5
2 2 3 7

输出

2

二维代码

#include <bits/stdc++.h>
using namespace std;

const int N = 100;

int n, m;
int f[N][N];

int main() {
    
    cin >> n >> m;
    /*
	只能将f[0][0] 初始化为 1, 这样才能保证当 j 恰好等于物品体积时才有方案数可加。
	其余均加 0, 即不满足恰好等于
	*/
    f[0][0] = 1;
    
    for (int i = 1; i <= n; i ++ ) {
        int v; 
        cin >> v;
        for (int j = 0; j <= m; j ++ ) {
            f[i][j] = f[i-1][j];
            if (j >= v) f[i][j] += f[i-1][j-v];
        }
    }
    
    cout << f[n][m];
    
    return 0;
}

状态压缩

#include <bits/stdc++.h>
using namespace std;

const int N = 100;

int n, m;
int f[N];

int main() {
    
    cin >> n >> m;
    
    f[0] = 1;
    for (int i = 1; i <= n; i ++ ) {
        int v; 
        cin >> v;
        for (int j = m; j >= v; j -- ) {
            f[j] += f[j - v];
        }
    }
    
    cout << f[m];
    
    return 0;
}

完全背包问题

例子:给你一堆物品,每个物品有一定的体积,每个物品可以选无数多个,求总体积恰好是 m 的方案数

输入

3 5
2 3 7

输出

1

二维代码

#include <iostream>

using namespace std;

const int N = 110;

int n, m;
int f[N][N];

int main()
{
    cin >> n >> m;
    f[0][0] = 1;
    for (int i = 1; i <= n; i ++ )
    {
        int v;
        cin >> v;
        for (int j = 0; j <= m; j ++ )
        {
            f[i][j] = f[i - 1][j];
            if(j >= v) f[i][j] += f[i][j - v];
        }
    }

    cout << f[n][m];

    return 0;
}

状态压缩

#include <iostream>

using namespace std;

const int N = 110;

int n, m;
int f[N];

int main()
{
    cin >> n >> m;
    f[0] = 1;
    for (int i = 1 ;i <= n; i ++ )
    {
        int v;
        cin >> v;
        for (int j = v ;j <= m; j ++ )
        {
            f[j] = f[j] + f[j - v];
        }
    }

    cout << f[m] << endl;

    return 0;
}

☆情况三:从前 i 个物品中选,且总体积至少是 j 的总方案数,初始化是 f[0][0] = 1, 其余是 0(至少的情况,j需要从0枚举到m,或者从m枚举到0)

01背包

例子:给你一堆物品,每个物品有一定的体积,每个物品只能选一个,求总体积至少是m的方案数

输入

3 5
2 3 7

输出

5

二维代码

#include <bits/stdc++.h>
using namespace std;

const int N = 110;

int n, m;
int f[N][N];

int main() {
    
    cin >> n >> m;
    
    f[0][0] = 1;
    
    for (int i = 1; i <= n; i ++ ) {
        int v;
        cin >> v;
        for (int j = 0; j <= m; j ++ ) {
            f[i][j] = f[i - 1][j] + f[i - 1][max(0, j - v)];
        }
    }
    
    cout << f[n][m];
    
    return 0;
}

状态压缩

#include <bits/stdc++.h>
using namespace std;

const int N = 110;

int n, m;
int f[N];

int main() {
    
    cin >> n >> m;
    
    f[0] = 1;
    
    for (int i = 1; i <= n; i ++ ) {
        int v;
        cin >> v;
        for (int j = m; j >= 0; j -- ) {
            f[j] += f[max(0, j - v)];
        }
    }
    
    cout << f[m];
    
    return 0;
}

完全背包

例子:给你一堆物品,每个物品有一定的体积,每个物品可以选无数多个,求总体积至少是 m 的方案数

答案:无穷多种方案数

求方案数初始化总结

二维实现以及状态压缩

1、体积至多 j,f[0][i] = 1, 0 <= i <= m,其余是0 , 状态压缩后:f[i] = 1, 0 <= i <= m,
2、体积恰好 j,f[0][0] = 1, 其余是0, 状态压缩后:f[0] = 1, 其余是0
3、体积至少 j,f[0][0] = 1,其余是0, 状态压缩后:f[0] = 1, 其余是0

如有错误之处,欢迎各位指正~~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值