博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
背包dp
阅读量:5224 次
发布时间:2019-06-14

本文共 3722 字,大约阅读时间需要 12 分钟。

一大波模板正在靠近

1.01背包

问题:有n件物品和一个容量为v的背包,第i件物品的费用(即体积)是w[i],价值是v[i],求解将哪些物品装入背包可使这些物品的费用和不超过背包容量,且价值总和最大。

动态转移方程为f[j]=max(f[j],f[j-w[i]]+v[i]),注意关于背包容量要倒着循环,来保证每个物品只选一次

//二维 for(int i=1;i<=n;i++)    for(int j=m;j>=0;j--)        f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);cout<
//一维 for(int i=1;i<=n;i++)    for(int j=m;j>=0;j--)        f[j]=max(f[j],f[j-w[i]]);cout<

2.完全背包

问题:有n种物品和一个容量为v的背包,每种物品都有无限件可用,第i种物品的费用是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

动态转移方程为f[j]=max(f[j],f[j-w[i]]+v[i]),完全背包问题与01背包问题只有背包容量的循环次序不同

/*完全背包(无限件可用)*/ for(int i=1;i<=n;i++)    for(int j=w[i];j<=m;j++)        f[j]=max(f[j],f[j-w[i]]+v[i]);

3.多重背包

问题:有n种物品和一个容量为v的背包,第i种物品最多有s[i]件可用,每件的费用是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

//朴素算法 for(int i=1;i<=n;i++)    for(int j=m;j>=0;j--)        for(int k=0;k<=s[i];k++)        {            if(j-w[i]*k<0)break;            f[j]=max(f[j],f[j-w[i]*k]+v[i]*k);        }cout<
//二进制优化,转换为01背包int n1=0;for(int i=1;i<=n;i++){    cin>>vv>>ww>>s;    int t=1;    while(s>=t)    {        w[++n1]=ww*t;        v[n1]=vv*t;        s-=t;        t*=2;    }    w[++n1]=ww*s;    v[n1]=vv*s;}for(int i=1;i<=n1;i++)    for(int j=m;j>=w[i];j--)        f[j]=max(f[j],f[j-w[i]]+v[i]);cout<

4.混合三种背包问题

问题:有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包),该怎么求解呢?

//朴素 for(int i=1;i<=n;i++){    if(s[i]==-1)//完全背包     {        for(int j=w[i];j<=m;j++)            f[j]=max(f[j],f[j-w[i]]+v[i]);    }    else    {        for(int k=1;k<=s[i];k++)//循环件数             for(int j=m;j>=w[i];j--)                f[j]=max(f[j],f[k-w[i]]+v[i]);    }}cout<
//二进制优化 for(int i=1;i<=n;i++){        int ww,vv,ss;    int t=1;    cin>>ww>>vv>>ss;    if(ss==-1)    {w[++n1]=ww;v[n1]=vv;s[n1]=-1;continue;}    if(ss==1)    {w[++n1]=ww;v[n1]=vv;s[n1]=1;continue;}    if(ss>1)//多重背包     {        int t=1;        while(ss>=t)        {            w[++n1]=ww*t;            v[n1]=vv*t;            s[n1]=1;            ss-=t;            t*=2;        }        if(ss>0){            w[++n1]=ww*ss;        v[n1]=vv*ss;        s[n1]=1;        }        continue;    }}for(int i=1;i<=n1;i++){    if(s[i]==-1)//完全背包     {        for(int j=w[i];j<=m;j++)            f[j]=max(f[j],f[j-w[i]]+v[i]);    }    else    {        for(int j=m;j>=w[i];j--)                f[j]=max(f[j],f[j-w[i]]+v[i]);    }}    cout<

5.二维费用背包

问题:二维费用的背包问题是指对于每件物品,具有两种不同的费用,选择这件物品必须同时付出这两种代价,对于每种代价都有一个可付出的最大值(背包容量),求选择物品可以得到最大的价值。设第i件物品所需的两种代价分别为w1[i]和w2[i],两种代价可付出的最大值(两种背包容量)分别为V和U,物品的价值为v[i]。

状态转移方程为:

f[i][j][k]=max(f[i-1][j][k],f[i-1][j-w1[i]][k-w2[i]]+v[i]);

/*二维费用的背包问题(与01背包相似)*/ for(int i=1;i<=n;i++)    for(int j=m1;j>=w1[i];j--)        for(int k=m2;k>=w2[i];k--)            f[j][k]=max(f[j-w1[i]][k-w2[i]],f[i][j]);cout<

6.分组背包

问题:有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

算法:

这个问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。也就是说设f[k][v]表示前k组物品花费费用v能取得的最大权值,则有:
f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于组k}
使用一维数组的伪代码如下:
for 所有的组k//循环分组
    for v=V..0//容量限制                                                                                                                                                                                       
        for 所有的i属于组k//组内物品
            f[v]=max{f[v],f[v-c[i]]+w[i]}

/*分组的背包问题*/ for(int i=1;i<=n;i++){    int p;    cin>>w[i]>>v[i]>>p;    a[p][++a[p][0]]=i;}for(int k=1;k<=t;k++)    for(int j=m;j>=0;j--)        for(int i=1;i<=a[k][0];i++)        {            int tmp=a[k][i];//tmp代表k组中的第i个物品在所有物品中的序号             f[j]=max(f[j],f[j-w[tmp]]+v[tmp]);         }cout<

7.背包问题的方案总数

对于一个给定了背包容量、物品费用的背包问题,除了再给定每个物品的价值后求可得到的最大价值外,还可以得到装满背包或将背包装至某一指定容量的方案总数。对于这类改变问法的问题,一般只需将状态转移方程中的max改成sum即可。例如若每件物品均是0-1背包中的物品,转移方程即为f[j]=sum{f[j],f[j-w[i]]+v[i]},即f[j]+=f[j-w[i]],初始条件f[0]=1。

事实上,这样做可行的原因在于状态转移方程已经考察了所有可能的背包组成方案.

/*背包问题的方案总数*/ //01背包求方案总数 for(int i=1;i<=n;i++)    for(int j=m;j>=w[i];j++)    f[j]+=f[j-w[i]];cout<

 

转载于:https://www.cnblogs.com/thmyl/p/7359371.html

你可能感兴趣的文章
JavaScript:学习笔记(7)——VAR、LET、CONST三种变量声明的区别
查看>>
JavaScript 鸭子模型
查看>>
PHP典型功能与Laravel5框架开发学习笔记
查看>>
SQL Server 如何查询表定义的列和索引信息
查看>>
GCD 之线程死锁
查看>>
NoSQL数据库常见分类
查看>>
信息安全系统设计基础实验四—20135214万子惠20135227黄晓妍
查看>>
一题多解 之 Bat
查看>>
Java 内部类
查看>>
测试一个对象是否是类字符串
查看>>
{面试题7: 使用两个队列实现一个栈}
查看>>
[转]SQL中 OVER(PARTITION BY) 取上一条,下一条等
查看>>
前端开发就从认识浏览器开始 - 浏览器处理请求的过程
查看>>
【练习】使用事务和锁定语句
查看>>
centos7升级firefox的flash插件
查看>>
jmeter系列二(jmeter engine相关)
查看>>
前端页面设计问题小计
查看>>
一份超全超详细的 ADB 用法大全
查看>>
Spring定时任务(@Scheduled)
查看>>
WebView 调试
查看>>