多重背包和分组背包

简介: 多重背包和分组背包

多重背包问题 I

有 N种物品和一个容量是 V 的背包。


第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。


求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。

输出最大价值。


输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。


接下来有 N 行,每行三个整数 vi,wi,si用空格隔开,分别表示第 i 种物品的体积、价值和数量。


输出格式

输出一个整数,表示最大价值。


数据范围

0<N,V≤100

0<vi,wi,si≤100


输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10

思路:多重背包和完全背包问题区别于物体数量上有明确的限制,暴力的做法就是,我们可以在完全背包的基础上加上一层循环 。

因为

f[j]=max(f[j],f[j-s[i]]+v[i],f[j-2*s[i]]+2*v[i],f[j-3*s[i]]+3*v[i],......,f[j-k*s[i]]+k*v[i]);

完整代码:

#include <iostream>
using namespace std;
const int N=110;
int f[N],s[N],v[N],num[N];
 
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>s[i]>>v[i]>>num[i];
    for(int i=1;i<=n;i++)
        for(int j=m;j>=s[i];j--)
            for(int k=0;k<=num[i]&&k*s[i]<=j;k++)  
            {
                f[j]=max(f[j],f[j-k*s[i]]+k*v[i]);
            }
    cout<<f[m];
}

多重背包问题 II

有 N种物品和一个容量是 V的背包。


第 i种物品最多有 si件,每件体积是 vi,价值是 wi。


求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。

输出最大价值。


输入格式

第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。


接下来有 N 行,每行三个整数 vi,wi,si用空格隔开,分别表示第 i 种物品的体积、价值和数量。


输出格式

输出一个整数,表示最大价值。


数据范围

0<N≤1000

0<V≤2000

0<vi,wi,si≤2000

输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10

思路:这里和第一个背包问题是一样的,区别在于数据量大了,所以暴力做法会TLE,然后可以用二进制优化方法。


其实就是将多重背包问题转换成01背包问题,可以这么想:每个物体有多个,那么我把所有拿物体的方式枚举出来添加到原来的问题组上,那么所有的物体就变成了数量唯一。


优化方法就在于不用枚举所有的方式,只要包括可以组成他所有数的“子数”(这个表达方式可能不太对),例如7,我们只需要插入1 ,2,4  就可以组成7以内的所有数,这里想一下二进制的表示方式。

完整代码:

#include <iostream>
#include <vector>
using namespace std;
const int N=2010;
int f[N];
struct Good{
    int v,w;
};
int main(){
    int n,m,v,w,s;
    cin>>n>>m;
    vector<Good> goods;
    for(int i=1;i<=n;i++)
    {
        cin>>v>>w>>s;
       for(int j=1;j<=s;j*=2)
        {
            s-=j;
            goods.push_back({j*v,j*w});
        } 
        goods.push_back({s*v,s*w});
    }
    for(auto good:goods)
    {
        for(int j=m;j>=good.v;j--)
        {
            f[j]=max(f[j],f[j-good.v]+good.w);
        }
    }
    cout<<f[m];  
            
}

分组背包

有 N 组物品和一个容量是 V 的背包。


每组物品有若干个,同一组内的物品最多只能选一个。

每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。


求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。


输出最大价值。


输入格式

第一行有两个整数 N,V用空格隔开,分别表示物品组数和背包容量。


接下来有 N 组数据:


每组数据第一行有一个整数 Si表示第 i 个物品组的物品数量;

每组数据接下来有 Si行,每行有两个整数 vij,wij用空格隔开,分别表示第 i个物品组的第 j 个物品的体积和价值;

输出格式

输出一个整数,表示最大价值。


数据范围

0<N,V≤100

0<Si≤100

0<vij,wij≤100

输入样例
3 5
2
1 2
2 4
1
3 4
1
4 5
输出样例:
8

思路:把分组背包理解成多层背包

每一个组--->>一个物体,

一个组内有多个物体--->>一个物体数量有多个

完整代码:

#include <iostream>
using namespace std;
const int N=110;
int f[N],v[N],w[N];
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        int s;
        cin>>s;
        for(int j=1;j<=s;j++)
            cin>>v[j]>>w[j];
        for(int j=m;j>=0;j--)
        {
            for(int k=1;k<=s;k++)
            {
                if(j>=v[k])
                f[j]=max(f[j],f[j-v[k]]+w[k]);
            }
        }
    }
    cout<<f[m];
}
相关文章
|
缓存 关系型数据库 MySQL
服务器磁盘爆满?别慌,教你轻松清理!
服务器磁盘空间告急?别慌!本文将教你如何快速识别并清理占用大量磁盘空间的文件和目录,优化日志文件,释放磁盘空间,恢复系统正常运行。适合服务器管理员和网站运营者。
1946 1
 服务器磁盘爆满?别慌,教你轻松清理!
|
数据可视化 Python
流形学习(Manifold Learning)是一种非线性降维方法
流形学习(Manifold Learning)是一种非线性降维方法
428 24
|
索引 Python
Pandas中的时间序列利器:set_index用法
Pandas中的时间序列利器:set_index用法
859 0
|
Python
干货文:在 Mac 中卸载 Python 的方式
干货文:在 Mac 中卸载 Python 的方式
3119 1
阿里十年大数据专家谈“云上数据中台之道”含内部PPT
从大数据的概念被正式提出,到马云老师预言人类正从IT时代走向DT时代,大数据浪潮迭起。大数据同仁共同认知的一点是,大数据会对社会创新、产业变革、业务创新及每个人的角色定位产生近乎决定性的影响。
|
网络协议 测试技术 开发工具
大学生学计算机科学或者软件工程,未来有哪些职业发展路径?
@[TOC](目录) 计算机科学和软件工程是大学中非常受欢迎的专业,这两个专业涉及到许多技术和领域,因此有很多职业发展路径可供选择。以下是超过 20 种职业选择及其对应的技能要求: # 1. 软件开发工程师: 掌握编程语言,如 Java、Python、C++ 等;熟练掌握软件开发工具和技术,如 IDE、版本控制工具、测试工具等;具备良好的代码编写和架构设计能力。 # 2. 计算机网络工程师: 熟悉网络协议和架构,如 TCP/IP、HTTP、HTTPS 等;掌握网络管理和监控工具,如 Wireshark、Nagios 等;具备良好的故障排除和问题解决能力。 # 3. 数据库管理员: 熟悉数据库
1020 0
|
SQL 机器学习/深度学习 开发框架
分享106个ASP新闻文章源码,总有一款适合您
分享106个ASP新闻文章源码,总有一款适合您
163 1
|
机器学习/深度学习 存储 算法
最邻近规则分类 KNN (K-Nearest Neighbor)算法及python实现
最邻近规则分类 KNN (K-Nearest Neighbor)算法及python实现
303 0
|
存储 安全 算法
并发编程-03线程安全性之原子性(Atomic包)及原理分析
并发编程-03线程安全性之原子性(Atomic包)及原理分析
203 0
|
前端开发 程序员