01背包&完全背包

·01背包&完全背包基础

01背包模型:给定n个物品,第i个物品体积为Wi,价值为Vi,背包容量为sum,选择一些物品放入背包,要求总价值最大。

F[i,j]表示前i个物品放入容量为j的包里获得的最大价值。

对于任意一个物品都有两种状态,要么放要么不放,不放的话很显然价值同前,放的话就要从包里拿出一部分体积。

完全背包模型:给定n种物品,第i个物品体积为Wi,价值为Vi,背包容量为sum,选择一些物品放入背包,要求总价值最大。

F[i,j]表示前i种物品放入容量为j的包里获得的最大价值

01背包方程:f[i,j]=max(f[i-1,j],f[i-1,j-Wi]+V[i]) (if j>=Wi)

完全背包方程:f[i,j]=max(f[i,j],f[i-1,j-Wi]+V[i]) (if j>=Wi)

目标:max{f[N][j](0<=j<=sum)}

 1 #include<iostream>
 2 using namespace std;
 3 int n,sum;
 4 int f[100][11000];
 5 int w[1100],v[1100];
 6 int main()
 7 {
 8     cin>>n>>sum;
 9     for(int i=1;i<=n;i++)
10         cin>>w[i]>>v[i];
11     f[0][0]=0;
12     for(int i=1;i<=n;i++)
13         for(int j=0;j<=sum;j++)
14         {
15             if(j>=w[i])f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
16             else f[i][j]=f[i-1][j];
17         }
18     cout<<f[n][sum];
19     return 0;
20 } 

01背包普通二维

由于01背包中每一阶段的i状态只与上一阶段的i-1有关,于是就可以用滚动数组降低空间开销啦~

在所有f__的第一维里全部都加上&,使dp状态从f[0]_和f[1]_中交替。

 1 #include<iostream>
 2 using namespace std;
 3 int n,sum;
 4 int f[3][11000];
 5 int w[1100],v[1100];
 6 int main()
 7 {
 8     cin>>sum>>n;
 9     for(int i=1;i<=n;i++)
10         cin>>w[i]>>v[i];
11     f[0][0]=0;
12     for(int i=1;i<=n;i++)
13         for(int j=0;j<=sum;j++)
14         {
15             if(j>=w[i])f[i&1][j]=max(f[(i-1)&1][j],f[(i-1)&1][j-w[i]]+v[i]);
16             else f[i&1][j]=f[(i-1)&1][j];
17         }
18     cout<<f[n&1][sum];
19     return 0;
20 } 

01背包之滚动数组

写到这里也很明确了,F数组的第一维完全可以省略,则F[j]表示背包中放入体积为j的物品的最大价值。

强调01背包的倒叙循环,完全背包的正序循环,因为01背包的转移是从i-1->i,而完全背包是i之间的转移。

循环到j时:

1.F数组后半段 f[j..m]处于第i个状态,已考虑过i

2.F前半段f[0...j-1]处于i-1个状态,未考虑过i

则j不断减小就意味着从i-1->i状态的转移。

(还可以初始化f为0,代表未放入物品时价值为0)

 1 #include<iostream>
 2 using namespace std;
 3 int n,sum;
 4 int f[11000];
 5 int w[1100],v[1100];
 6 int main()
 7 {
 8     cin>>n>>sum;
 9     for(int i=1;i<=n;i++)
10         cin>>w[i]>>v[i];
11     for(int i=1;i<=n;i++)
12         for(int j=sum;j>=w[i];j--)
13             f[j]=max(f[j],f[j-w[i]]+v[i]);
14     cout<<f[sum];
15     return 0;
16 }

01背包

 1 #include<iostream>
 2 using namespace std;
 3 int n,sum;
 4 int f[11000];
 5 int w[1100],v[1100];
 6 int main()
 7 {
 8     cin>>n>>sum;
 9     for(int i=1;i<=n;i++)
10         cin>>w[i]>>v[i];
11     for(int i=1;i<=n;i++)
12         for(int j=w[i];j<=sum;j++)
13             f[j]=max(f[j],f[j-w[i]]+v[i]);
14     cout<<f[sum];
15     return 0;
16 }

完全背包


·01背包应用

栗1:给定n个正整数,从中选出若干个使它们和为sum,求方案数。

f[j]表示和为j的方案数有多少

 1 #include<iostream>
 2 #define MAXN 1100
 3 using namespace std;
 4 int f[MAXN],a[MAXN];
 5 int main()
 6 {
 7     int n,sum;
 8     cin>>n>>sum;
 9     for(int i=1;i<=n;i++)
10         cin>>a[i];
11     f[0]=1;
12     for(int i=1;i<=n;i++)
13         for(int j=sum;j>=a[i];j--)
14             f[j]+=f[j-a[i]];
15     cout<<f[sum];
16 }

数字组合

栗2:给定n个物品,体积是Vi,质量为Wi,价值为Ki,给定体积为SUM,负载量为M的背包,在体积载量允许的情况下求最大价值。

还是简单的01背包,不过是体积多个维度而已;

 1 #include<iostream>
 2 using namespace std;
 3 int v[51],w[51],k[51],f[401][401];
 4 int main()
 5 {   int n,sum,m;
 6     cin>>n>>sum>>m;
 7     for(int i=1;i<=n;i++)
 8         cin>>v[i]>>w[i]>>k[i];
 9     for(int i=1;i<=n;i++)
10         for(int j=sum;j>=v[i];j--)
11             for(int l=m;l>=w[i];l--)
12                 f[j][l]=max(f[j][l],f[j-w[i]][l-w[i]]+k[i]);
13     cout<<f[sum][m];
14     return 0;
15 }

多维01背包


·完全背包应用

给定自然数n,把n拆分成几个正整数相加的形式,数可以重复使用,求方案数。

相当于n个物体,体积分别是1,2,3..n,背包容量为n,每个物品可重复使用,用板子就好了,求和类似于上面数字组合。

 1 #include<iostream>
 2 using namespace std;
 3 int f[1100];
 4 int main()
 5 {
 6     int n;
 7     cin>>n;
 8     f[0]=1;
 9     for(int i=1;i<=n;i++)
10         for(int j=1;j<=n;j++)
11             f[j]=f[j]+f[j-1];
12     cout<<f[n];
13 }

自然数拆分

原文地址:https://www.cnblogs.com/S-Gloria/p/11824116.html

时间: 2025-01-29 15:04:20

01背包&完全背包的相关文章

HDU 3033 I love sneakers! (DP 01背包+完全背包)

Problem Description After months of hard working, Iserlohn finally wins awesome amount of scholarship. As a great zealot of sneakers, he decides to spend all his money on them in a sneaker store. There are several brands of sneakers that Iserlohn wan

HDU2191_悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(背包/多重背包)

解题报告 题目传送门 题意: 中文不多说; 思路: 基础多重背包,每个物品有多个可以选,转换成01背包解. #include <iostream> #include <cstring> #include <cstdio> #define inf 99999999 using namespace std; int main() { int t,i,j,n,m,v,p,h,cc,w[1010],c[1010],dp[1010]; scanf("%d",&

POJ3260——The Fewest Coins(多重背包+完全背包)

The Fewest Coins DescriptionFarmer John has gone to town to buy some farm supplies. Being a very efficient man, he always pays for his goods in such a way that the smallest number of coins changes hands, i.e., the number of coins he uses to pay plus

ZOJ 3164 Cookie Choice 分组背包 混合背包

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3181 题意: 就是混合背包加分组背包,有的物品是01背包,有的是多重背包,有的是完全背包,同时物品还有不超过8组的分组,如果在同一组则最多只能选一种.问能不能恰好地用掉D的容量,并且使所获价值最大. 分析: 开始的想法是多开一个下标,先把没有分组的做了,在0的下标,然后分组分别在组号的下标里按顺序处理,是什么背包就用什么做法,不过一直WA,对拍小数据大数据都没啥问题(可能随机

HDU1114_Piggy-Bank(背包/完全背包)

解题报告 题目传送门 题意: 给金币的面额和重量,求装满储蓄罐的最小价值. 思路: 完全背包基础,初始dp为最大,dp[0]=0表示储蓄罐为空价值为0; 状态转移方程就是dp[j]=min(dp[j],dp[j-w[i]]+c[i]) #include <iostream> #include <cstring> #include <cstdio> #define inf 99999999 using namespace std; int main() { int t,i

POJ 3260 多重背包+完全背包

前几天刚回到家却发现家里没网线 && 路由器都被带走了,无奈之下只好铤而走险尝试蹭隔壁家的WiFi,不试不知道,一试吓一跳,用个手机软件简简单单就连上了,然后在浏览器输入192.168.1.1就能看到他的路由器的一切信息,包括密码,然后打开笔记本……好了,废话不多说,能连上网后第一时间当然是继续和队友之前约好的训练了. 今天翻看到之前落下的一道混合背包题目,然后在草稿本上慢慢地写递推方程,把一些细节细心地写好…(本来不用太费时间的,可是在家嘛,一会儿妈走来要我教她玩手机,一会儿有一个亲戚朋

HDU1248_寒冰王座(背包/完全背包)

解题报告 题目传送门 无聊的水题. #include <iostream> #include <cstring> #include <cstdio> #define inf 0x3f3f3f3f using namespace std; int c[10100],w[10100],dp[11000],v,n; int main() { int t,i,j; scanf("%d",&t); while(t--) { memset(dp,0,si

B 二维背包+完全背包 Hdu2159

<span style="color:#3333ff;">/* ------------------------------------------------------------------------------------------------ author : Grant Yuan time : 2014.7.19 aldorithm: 二维背包+完全背包 ----------------------------------------------------

B 维背包+完全背包 Hdu2159

<span style="color:#3333ff;">/* ------------------------------------------------------------------------------------------------ author : Grant Yuan time : 2014.7.19 aldorithm: 二维背包+全然背包 ----------------------------------------------------