裸0-1背包,背包入门 主要是背包基础打打好,还有空间复杂度优化(还不会,会了再回来写)
输入:数据组数t,每组数据有3行。
第一行三个数据,背包空间,目标价值和物品数量。
第二行n个数据表示n个物品所占空间
第三行n个数据表示n个物品的价值
输出:若最大价值达到目标价值,输出“YES” 否则输出“NO”
样例输入:
1
6 20 4
1 2 3 2
4 6 12 7
样例输出:
Case #1: YES
解题思路:DP思想,ans[a][b]表示的意思是b个空间的情况下考虑前a个物品能放的最大价值。所以a=0和b=0的时候ans[a][b]都是0。最重要的是状态转移方程,即ans[a][b] = max(ans[a-1][b],w[a]+ans[a-1][V-v[a]] 前者为“不选a",后者为选a。(当然,之前要判断一下V和v[a]的大小) 这样两重循环,外循环循环V,内循环循环物品数量,n^2解决问题。详见代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <cctype>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
#define ll long long
#define INF 1000000000
int gcd(int a,int b){return b==0? a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;}
int ans[110][1010];
int v[110];
int p[110];
int main()
{
int t;
int kase = 0;
scanf("%d",&t);
while(t--){
int V,tar,n;
scanf("%d%d%d",&V,&tar,&n);
for(int i = 1 ; i <= n ; i ++) scanf("%d",&v[i]);
for(int i = 1 ; i <= n ; i ++) scanf("%d",&p[i]);
for(int i = 0 ; i < n ; i ++){
ans[i][0] = 0;//0容积情况
ans[0][i] = 0;//没物品情况
}
for(int i = 1 ; i <= V ; i ++){//到i容积
for(int j = 1 ; j <= n ; j ++){//到第j个物品
if(v[j] > i) ans[j][i] = ans[j-1][i];
else ans[j][i] = max(ans[j-1][i],p[j]+ans[j-1][i-v[j]]);
}
}
printf("Case #%d: ",++kase);
if(ans[n][V] >= tar) printf("YES\n");
else printf("NO\n");
}
return 0;
}
这几天学会了一维数组解01背包,就拿这个题讲解一下吧~~
我们知道,动态规划的核心是状态转移方程。01背包的状态转移方程是
dp[i][j] = max(dp[i-1][j],dp[i-1][j-v[i]]+p[i])
仔细分析一下这个方程,会发现每次的求解过程会用到两个值dp[i-1][j]和dp[i-1][j-v[i]] 而这两个值恰恰都是考虑前i-1个元素。这样,我们可以使用滚动数组的技巧,让dp数组退化为一维的。需要注意的是,在遍历空间时必须倒着来遍历,不然就会影响到dp[j-v[i]]的计算
下面贴一下一维数组求解的代码。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <cctype>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
int gcd(int a,int b){return b == 0? a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;}
#define ll long long
#define INF 1000000000
const int maxn = 1010;
int dp[maxn];
int v[maxn];
int p[maxn];
int main()
{
int kase = 0;
int t;
scanf("%d",&t);
while(t--){
int V,tar,n;
scanf("%d%d%d",&V,&tar,&n);
for(int i = 1 ; i <= n ; i ++) scanf("%d",&v[i]);
for(int i = 1 ; i <= n ; i ++) scanf("%d",&p[i]);
for(int i = 0 ; i < maxn ; i ++) dp[i] = 0;
for(int i = 1 ; i <= n ; i ++){
for(int j = V ; j >= 0 ; j --){
if(j >= v[i]) dp[j] = max(dp[j],dp[j-v[i]]+p[i]);
}
}
if(dp[V] >= tar) printf("Case #%d: YES\n",++kase);
else printf("Case #%d: NO\n",++kase);
}
return 0;
}