☆☆☆ 求方案数问题
文章目录
前言
- 在看本篇目之前,确保你已经掌握了基础算法:背包问题详解
- 以及各种背包求价值的的模型:经典算法之背包求最大最小值问题
- 掌握了不同的基础背包模板后,试一下不同场景的应用:背包问题应用
☆情况一:从前 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
如有错误之处,欢迎各位指正~~~