模板【背包问题】

PART1(算法思想简介)

1.实现:

2.时间复杂度:

3.特别优势:

4.适用情况:

5.需要注意的点:

6:函数、变量名的解释+英文:

volume(体积)
quantity(数量)

PART2(算法各种类型(并附上代码))

 TYPE1 01背包:

普通解法:O(VN)【空间也是O(VN)】从1~n件物品,对已经用了j的空间的情况下尝试放入(其实可能没有用到这么多的空间,但这样的答案肯定更新不了最优解【大的空间放的东西肯定比小的空间多】,所以没关系啦),放得下的就放进去看能不能更新最优解。

#include <iostream>
#include <cstring>
using namespace std;
const int N = 21;
const int V = 1e3+10;
int bagDp[N][V];
int value[N], volume[N];
int main() {
    int n, v;
    cin >> n >> v;
    for(int i = 1;i <= n;i++){
        cin >> value[i] >> volume[i];
    }
    for(int i = 1;i <= n;i++){
        for(int j = 0;j <= v;j++){
            if(j >= volume[i]){//提前判断装不装得下
                bagDp[i][j] = max(bagDp[i - 1][j - volume[i]] + value[i],bagDp[i - 1][j]);
            }else {//要记得这个处理
                bagDp[i][j] = bagDp[i - 1][j];
            }
        }
    }
    cout << bagDp[n][v] <<endl;
    return 0;
}
View Code

 

空间压缩优化:O(VN)【但是空间是O(V)了】i物品存放本来是由i-1层跟新来的,但是如果j从V~1,因为dp[i][j]必然是由dp[i-1][j-v[i]]【也就是空间更小的更新来的】,我们就可以压缩一下,只需要一重dp[1~V]就成

#include <iostream>
#include <cstring>
using namespace std;
const int N = 21;
const int V = 1e3+10;
int bagDp[V];
int value[N], volume[N];
int main() {
    int n, v;
    cin >> n >> v;
    for(int i = 1;i <= n;i++){
        cin >> value[i] >> volume[i];
    }
    for(int i = 1;i <= n;i++){
        for(int j = v;j >= volume[i];j--){
            bagDp[j] = max(bagDp[j-volume[i]] + value[i], bagDp[j]);
        }
    }
    cout << bagDp[v] <<endl;
    return 0;
}
View Code

 

 TYPE1 多重背包:

普通解法:

 

 

#include <iostream>
#include <cstring>
using namespace std;
const int N = 21;
const int V = 1e3+10;
int bagDp[N][V];
int value[N], volume[N], quantity[N];
int main()
{
    int n, v;
    cin >> n >> v;
    for(int i = 1; i <= n; i++)
    {
        cin >> value[i] >> volume[i] >> quantity[i];
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = v; j >= volume[i]; j--)
        {
            for(int k = 0; k <= quantity[i]; k++)
                if(j >= volume[i]*k)
                    bagDp[i][j] = max(bagDp[i-1][j-volume[i]*k] + value[i]*k, bagDp[i][j]);
                else
                    break;
        }
    }
    cout << bagDp[n][v] <<endl;
    return 0;
}
View Code

 

空间压缩版本:只要J是逆序地就不重复覆盖(树上例题)

#include <iostream>
#include <cstring>
using namespace std;
const int N = 21;
const int V = 1e3+10;
int bagDp[V];
int value[N], volume[N], quantity[N];
int main()
{
    int n, v;
    cin >> n >> v;
    for(int i = 1; i <= n; i++)
    {
        cin >> value[i] >> volume[i] >> quantity[i];
    }
    for(int i = 1; i <= n; i++)//总共有t组 从第一组开始
    {
        for(int j = v; j >= volume[i]; j--)//背包容积剩余 j
        {
            for(int k = 0; k <= quantity[i]; k++)//这组里面有多少个元素
                if(j >= volume[i]*k)
                    bagDp[j] = max(bagDp[j-volume[i]*k] + value[i]*k, bagDp[j]);
                else
                    break;
        }
    }
    cout << bagDp[v] <<endl;
    return 0;
}
View Code

 

二进制优化:

根据把quantity[i]分解成二进制数来把其分成log(quantity[i])件物品

 

 

 TYPE1 无穷背包:

 用j来限制使得无穷背包转化为多重背包

 

 甚至,都不用枚举k了,用dp[i][v-c[i]]更新dp[i][v]就行

 

 

 空间优化:

 

 

 

#include <iostream>
#include <cstring>
using namespace std;
const int N = 21;
const int V = 1e3+10;
int bagDp[V];
int value[N], volume[N];
int main() {
    int n, v;
    cin >> n >> v;
    for(int i = 1;i <= n;i++){
        cin >> value[i] >> volume[i];
    }
    for(int i = 1;i <= n;i++){
        for(int j = volume[i];j <= v;j++){
            bagDp[j] = max(bagDp[j-volume[i]] + value[i], bagDp[j]);
        }
    }
    cout << bagDp[v] <<endl;
    return 0;
}
View Code

 

PART3(算法的延伸应用)

 

PART4(对算法深度的理解)

 

PART5(与其相关的有趣题目)

 

posted @ 2021-07-04 11:31  bear_xin  阅读(28)  评论(0编辑  收藏  举报