动态规划——背包问题

一:01背包

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

状态转移方程:f[i][v]=max{f[i-1][v],f[i-1][v-w[i]]+c[i]}

一维数组:f[v]=max{f[v],f[v-w[i]]+c[i]}

 

                                                           1267:【例9.11】01背包问题

【题目描述】

一个旅行者有一个最多能装 MM 公斤的背包,现在有 nn 件物品,它们的重量分别是W1,W2,...,WnW1,W2,...,Wn,它们的价值分别为C1,C2,...,CnC1,C2,...,Cn,求旅行者能获得最大总价值。

【输入】

第一行:两个整数,MM(背包容量,M≤200M≤200)和NN(物品数量,N≤30N≤30);

第2..N+12..N+1行:每行二个整数Wi,CiWi,Ci,表示每个物品的重量和价值。

【输出】

仅一行,一个数,表示最大总价值。

【输入样例】

10 4
2 1
3 3
4 5
7 9

【输出样例】

12

解法一:

#include<bits/stdc++.h>
using namespace std;
const int N=205;
int m,n;
int dp[N][N];
int w[N],v[N];
int main()
{
    cin>>m>>n;
    for(int i=1;i<=n;i++){
        cin>>w[i]>>v[i];
    }
    for(int i=1;i<=n;i++){
        for(int j=m;j>=0;j--){
         if(w[i]>j) dp[i][j]=dp[i-1][j];
         else dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
        }
    }
    cout<<dp[n][m]<<endl;

    return 0;
}

解法二:

#include<bits/stdc++.h>
using namespace std;
int dp[300];
int w[35],v[35];
int M,N;
int main()
{
    cin>>M>>N;
    for(int i=1;i<=N;i++)
        cin>>w[i]>>v[i];
    for(int i=1;i<=N;i++){
        for(int j=M;j>w[i];j--)
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    }
    cout<<dp[M]<<endl;

    return 0;
}

 

二:完全背包

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

 

其实就是01背包是逆序这个是正序,其他和01背包差不多

 

                            1268:【例9.12】完全背包问题

【题目描述】

设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。

【输入】

第一行:两个整数,M(背包容量,M≤200)和N(物品数量,N≤30);

第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。

【输出】

仅一行,一个数,表示最大总价值。

【输入样例】

10 4
2 1
3 3
4 5
7 9

【输出样例】

max=12

方法一:

#include<bits/stdc++.h>
using namespace std;
int M,N;
int f[35][250];
int w[34],c[35];

int main()
{
    cin>>M>>N;
    for(int i=1;i<=N;i++){
        cin>>w[i]>>c[i];
    }
    for(int i=1;i<=N;i++){
        for(int v=0;v<=M;v++){
            if(v<w[i]) f[i][v]=f[i-1][v];
            else f[i][v]=max(f[i-1][v],f[i][v-w[i]]+c[i]);
        }
    }
    cout<<"max="<<f[N][M]<<endl;

    return 0;
}

方法二:

#include<bits/stdc++.h>
using namespace std;
int M,N;
int f[250];
int w[34],c[35];

int main()
{
    cin>>M>>N;
    for(int i=1;i<=N;i++){
        cin>>w[i]>>c[i];
    }
    for(int i=1;i<=N;i++){
        for(int v=w[i];v<=M;v++){
            f[v]=max(f[v],f[v-w[i]]+c[i]);
        }
    }
    cout<<"max="<<f[M]<<endl;


    return 0;
}

 

三:多重背包

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

 

                                                                    

                                                           1269:【例9.13】庆功会

【题目描述】

为了庆贺班级在校运动会上取得全校第一名成绩,班主任决定开一场庆功会,为此拨款购买奖品犒劳运动员。期望拨款金额能购买最大价值的奖品,可以补充他们的精力和体力。

【输入】

第一行二个数n(n≤500),m(m≤6000),其中n代表希望购买的奖品的种数,m表示拨款金额。

接下来n行,每行3个数,v、w、s,分别表示第I种奖品的价格、价值(价格与价值是不同的概念)和能购买的最大数量(买0件到s件均可),其中v≤100,w≤1000,s≤10。

【输出】

一行:一个数,表示此次购买能获得的最大的价值(注意!不是价格)。

【输入样例】

5 1000
80 20 4
40 50 9
30 50 7
40 30 6
20 20 1

【输出样例】

1040

方法一:

#include<bits/stdc++.h>
using namespace std;
int f[6500];
int v[6500],w[6500],s[6500];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>v[i]>>w[i]>>s[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<k*v[i]) break;
                f[j]=max(f[j],f[j-k*v[i]]+k*w[i]);
            }
        }
    }
    cout<<f[m]<<endl;

    return 0;
}

方法二:进行二进制优化,转换为01背包

#include<bits/stdc++.h>
using namespace std;
int n,m,n1=0;
int f[6550];
int v[100000],w[100000];

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        int x,y,s,t=1;
        cin>>x>>y>>s;
        while(s>=t){
            v[++n1]=x*t;
            w[n1]=y*t;
            s-=t;
            t*=2;
        }
        v[++n1]=x*s;
        w[n1]=y*s;
    }
    for(int i=1;i<=n1;i++){
        for(int j=m;j>=v[i];j--){
            f[j]=max(f[j],f[j-v[i]]+w[i]);
        }
    }
    cout<<f[m]<<endl;
    return 0;
}

 

四:混合三种背包问题

如果将01背包,完全背包,多重背包混合起来,也就是说,有的物品只可以取一次(01),有的物品可以取无限次(完全背包),有的物品可以取得次数有一个上限(多重背包)

 

                                                   1270:【例9.14】混合背包

【题目描述】

一个旅行者有一个最多能装V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,WnW1,W2,...,Wn,它们的价值分别为C1,C2,...,CnC1,C2,...,Cn。有的物品只可以取一次(01背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包)。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

【输入】

第一行:二个整数,M(背包容量,M≤200),N(物品数量,N≤30);

第2..N+1行:每行三个整数Wi,Ci,PiWi,Ci,Pi,前两个整数分别表示每个物品的重量,价值,第三个整数若为0,则说明此物品可以购买无数件,若为其他数字,则为此物品可购买的最多件数(PiPi)。

 

【输出】

仅一行,一个数,表示最大总价值。

【输入样例】

10  3
2  1  0
3  3  1
4  5  4

【输出样例】

11

【提示】

选第一件物品1件和第三件物品2件。

#include<bits/stdc++.h>
using namespace std;
int m,n;
int w[35],c[35],p[35];
int f[250];
int main()
{
    cin>>m>>n;
    for(int i=1;i<=n;i++)
        cin>>w[i]>>c[i]>>p[i];
    for(int i=1;i<=n;i++){
        if(p[i]==1){//01
            for(int j=m;j>=w[i];j--)
                f[j]=max(f[j],f[j-w[i]]+c[i]);
        }
        else if(p[i]==0){//完全
            for(int j=w[i];j<=m;j++){
                f[j]=max(f[j],f[j-w[i]]+c[i]);
            }

        }
        else{//多重
            for(int j=m;j>=0;j--){
                for(int k=0;k<=p[i];k++){
                    if(j-k*w[i]>=0)
                    f[j]=max(f[j],f[j-k*w[i]]+k*c[i]);
                }
            }
        }
    }
    cout<<f[m]<<endl;
    return 0;
}

 

#include<bits/stdc++.h>
using namespace std;
int m,n;
int w[35],c[35],p[35];
int f[300];
int main()
{
    cin>>m>>n;
    for(int i=1;i<=n;i++){
        cin>>w[i]>>c[i]>>p[i];
    }
    for(int i=1;i<=n;i++){
        if(p[i]==0){//完全背包
            for(int j=w[i];j<=m;j++){
                f[j]=max(f[j],f[j-w[i]]+c[i]);
            }
        }
        else{//01背包和多重背包
            for(int j=1;j<=p[i];j++){
                for(int k=m;k>=w[i];k--)
                    f[k]=max(f[k],f[k-w[i]]+c[i]);
            }
        }
    }
    cout<<f[m]<<endl;
    return 0;
}

 

 

五:二维费用的背包问题

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

 

算法:

费用加了一维,只需要状态也加一维即可,设f[i][v][u]表示前i件物品付出俩种代价分别为V和U时得到的最大值

状态转移方程就是:f[i][v][u]=max(f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+ c[i])

同理可以转换成二维数组求解

 

                                                            

                                                  1271:【例9.15】潜水员

【题目描述】

潜水员为了潜水要使用特殊的装备。他有一个带2种气体的气缸:一个为氧气,一个为氮气。让潜水员下潜的深度需要各种的数量的氧和氮。潜水员有一定数量的气缸。每个气缸都有重量和气体容量。潜水员为了完成他的工作需要特定数量的氧和氮。他完成工作所需气缸的总重的最低限度的是多少?

例如:潜水员有5个气缸。每行三个数字为:氧,氮的(升)量和气缸的重量:

3 36 120

10 25 129

5 50 250

1 45 130

4 20 119

如果潜水员需要5升的氧和60升的氮则总重最小为249(1,2或者4,5号气缸)。

你的任务就是计算潜水员为了完成他的工作需要的气缸的重量的最低值。

【输入】

第一行有2整数m,n(1≤m≤21,1≤n≤79)。它们表示氧,氮各自需要的量。

第二行为整数k(1≤n≤1000)表示气缸的个数。

此后的k行,每行包括ai,bi,ci(1≤ai≤21,1≤bi≤79,1≤ci≤800)3ai,bi,ci(1≤ai≤21,1≤bi≤79,1≤ci≤800)3整数。这些各自是:第i个气缸里的氧和氮的容量及汽缸重量。

 

【输出】

仅一行包含一个整数,为潜水员完成工作所需的气缸的重量总和的最低值。

【输入样例】

5 60
5
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119

【输出样例】

249

 

其实就是相当于费用加了一维,只需状态也加一维即可,则设f[i][v][u]为前i件物品付出两种代价v和u时可获得的最大价值。

状态转移方程:f[i][v][u]=max(f[i][v][u],f[i-1][v-a[i]][u-b[i]]+c[i]),如01背包转化为一维问题一样,

转化为二维f[v][u]=max(f[v][u],f[v-a[i]][u-b[i]]+c[i]),

 

这题和01背包的区别是背吧问题是用背包空间,这个是得到最小重量

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n,m,i,k,j,f[102][102];
     int a[6002],b[6002],c[6002];
     cin>>m>>n>>k;
     int t;
     memset(f,127,sizeof(f));//把f初始化为一个很大的整数,我也纳闷127为啥,很大的整数
    for(i=1;i<=k;i++)
        cin>>a[i]>>b[i]>>c[i];
        f[0][0]=0;
       for(i=1;i<=k;i++)
        for(j=m;j>=0;j--)
        for(t=n;t>=0;t--)
       {
           int d1=j+a[i];//和01背包不同,它的a[i]和b[i]是可以超过的
           int d2=t+b[i];
           if(d1>m)  d1=m;//若氮 和氧含量超过需求,直接等于需求
           if(d2>n)  d2=n;
           f[d1][d2]=min(f[d1][d2],f[j][t]+c[i]);
       }
       cout<<f[m][n];
    return 0;
}
 
 

 

 

六:分组的背包问题

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

 

这个问题变成了每组物品有若干种策略:选择本组的某一件,还是一件都 不选。也就是说设f[k][v]表示前k组物品花费费用v能取得的最大权值,则有f[k][v]=max(f[k-1][v],f[k-1][v-w[i]]+c[i])物品i属于第k组

 

                                         1272:【例9.16】分组背包

【题目描述】

一个旅行者有一个最多能装V公斤的背包,现在有n件物品,它们的重量分别是W1,W2,...,WnW1,W2,...,Wn,它们的价值分别为C1,C2,...,CnC1,C2,...,Cn。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

【输入】

第一行:三个整数,V(背包容量,V≤200),N(物品数量,N≤30)和T(最大组号,T≤10);

第2..N+1行:每行三个整数Wi,Ci,PWi,Ci,P,表示每个物品的重量,价值,所属组号。

 

【输出】

仅一行,一个数,表示最大总价值。

【输入样例】

10 6 3
2 1 1
3 3 1
4 8 2
6 9 2
2 8 3
3 9 3

【输出样例】

20
#include<bits/stdc++.h>
using namespace std;
int w[31],c[31];
int a[11][31],f[201];
int v,n,t;
int main()
{
    scanf("%d%d%d",&v,&n,&t);
    for(int i=1;i<=n;i++){
        int p;
        scanf("%d%d%d",&w[i],&c[i],&p);
        a[p][++a[p][0]]=i;//a[p][0]存储p组元素个数,a[p][x] 是存储元素序号
    }
    for(int k=1;k<=t;k++){
        for(int j=v;j>=0;j--){
            for(int i=1;i<=a[k][0];i++){
                if(j>=w[a[k][i]]){
                    int temp=a[k][i];
                    f[j]=max(f[j],f[j-w[temp]]+c[temp]);
                }

            }
        }
    }
    printf("%d\n",f[v]);
    return 0;
}

 

 

七:背包问题的方案总数

对于一个给定了背包容量,物品费用,物品间相互关系(分组,依赖等)的背包问题,除了在给定每个物品的价值后求可得到的最大价值外,还可以得到装满背包或将背包装某一指定容量的方案总数

 

                                           1273:【例9.17】货币系统

【题目描述】

给你一个n种面值的货币系统,求组成面值为m的货币有多少种方案。

【输入】

第一行为n和m。

【输出】

一行,方案数。

【输入样例】

3 10        //3种面值组成面值为10的方案
1           //面值1
2           //面值2
5           //面值5

【输出样例】

10          //有10种方案

 

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[10100];
long long int f[1000001];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    f[0]=1;
    for(int i=1;i<=n;i++){
        for(int j=a[i];j<=m;j++){
            f[j]+=f[j-a[i]];
        }
    }
    printf("%lld\n",f[m]);
    return 0;
}

 

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
动态规划是一种将大问题分解为小问题进行解决的方法,背包问题动态规划中最经典的题型之一。背包问题分为三类:01背包、完全背包和多重背包。其中,01背包问题是最经典的背包问题,也是动态规划的入门级必学算法。\[1\] 动态规划解决背包问题的核心思想是将问题分解为若干个小问题,先求解子问题,然后从子问题的解得到原问题的解。与分治法不同的是,动态规划适用于有重叠子问题的情况,即下一阶段的求解是建立在上一阶段的解的基础上进行进一步求解。通过填表的方式,逐步推进,最终得到最优解。\[2\] 多重背包问题介于01背包和完全背包之间,可以将其转化为01背包或完全背包问题来求解。对于某种物品,如果其数量乘以单位体积大于背包总容量,那么该物品与背包之间是完全背包问题。而对于某种物品,可以将其数量视为不同的物品,然后按照01背包问题进行处理。这样的转化可以在数据范围较小时适用,但在数量较大时可能会导致超时。因此,可以采用更精炼的划分方案,如二进制拆分,来减少物品分类的组数,从而优化算法的效率。\[3\] 总结来说,动态规划是一种解决背包问题的有效方法,通过将大问题分解为小问题,并利用子问题的解来求解原问题,可以得到背包的最优解。 #### 引用[.reference_title] - *1* *3* [【算法与数据结构】—— 动态规划背包问题](https://blog.csdn.net/the_ZED/article/details/104882665)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [动态规划算法解决经典背包问题](https://blog.csdn.net/m0_52110974/article/details/120122061)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值