背包
背包问题就是我感觉很好理解的一个题目,可能是以前的dp的理解真的对于我而已有点难接受的比较慢在运用到题目中更是难上加难的,但是背包这个问题我感觉很好找到定位
01背包问题和完全背包和多重背包问题
我认为就是简单的记住一个公式就好,往里面套
其中的v表示包容量,然后c[i]表示的就是那个物体所占的容量,然后加其价值,进行比较就好了。然后完全背包和背包问题唯一差别就是完全背包问题可以无数的使用,多重背包和01背包、完全背包的区别就是多重背包中每个物品的个数都是给定的,可能不是一个,绝对不是无限个。然后就是上题目对题目的运用吧。
题目:https://vjudge.net/contest/367645#problem/S
最近,我去了一个古老的国家。在很长一段时间里,它是世界上最富有、最强大的王国。结果,这个国家的人民仍然非常自豪,即使他们的国家不再那么富有。商人是最典型的,他们每个人只卖一件商品,价格是Pi,但是如果你的钱少于Qi,他们就会拒绝和你交易,而我评估每件商品的价值Vi。如果他有M单位的钱,iSea能得到的最大值是多少?
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Max(a,b) a>b?a:b
using namespace std;
struct node
{
int a,b,c;
}s[555];
bool cmp(const node &a,const node &b)
{
return a.b-a.a<b.b-b.a;
}
int main (void)
{
int n,m,i,j,k,l;
int dp[5555];
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=0;i<n;i++)
{
scanf("%d%d%d",&s[i].a,&s[i].b,&s[i].c);
}
sort(s,s+n,cmp);
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++)
for(j=m;j>=s[i].b;j--)
dp[j]=Max(dp[j],dp[j-s[i].a]+s[i].c);
printf("%d\n",dp[m]);
}
return 0;
}
这个题目是来自一个我看的博客,最近比较喜欢乱看博客,感觉还行就收藏一下,哈哈哈哈,多看点可能应该就会多了。
这是多重问题,对与多重背包可以将进行自己初步的简化,多重背包的将其i个物品分开这样就可以得到1–i个物品,然后接下来就是对其进行01背包问题的做法了。还有优化的模式,二进制优化,第i种物品是有n[i]件的,这个n[i]可以被展开为n[i]=20+21+…+2k+c (其中2k+1 < n[i] < 2k+2),同时记录这些加数的值,那这样的话对于[0,n[i]]的每一个数,都可以用这些二进制数表示。即为将n种物品转化成cnt种物品【每种物品的可选择数量都是2的某次方(某种物品的最后一种例外)】
#include <bits/stdc++.h>
using namespace std;
struct E
{
int w; //体积
int v; //重量
} lis[2001];
int dp[101];
int main()
{
int T,n,m;
int p,h,k;
int i,j;
int index,c;
scanf("%d%d",&n,&m); //n表示容量,m表示种类
index = 0; //拆分后物品总数
for( i=1; i<=m; i++)
{
c = 1;
scanf("%d%d%d",&p,&h,&k); //p表示价格,h表示重量,k表示大米袋数。
while( k-c>0)
{
k -= c;
lis[++index].w = c*p;
lis[index].v = c*h;
c *= 2;
}
lis[++index].w = p*k; //补充不足指数的差值
lis[index].v = h*k;
}
for( i=0; i<=n; i++) dp[i]=0;
for( i=1; i<=index; i++) //对拆分后的物品进行0-1背包
{
for( j=n; j>=lis[i].w; j--)
dp[j] = max( dp[j],dp[j-lis[i].w]+lis[i].v);
}
printf("%d\n",dp[n]);
return 0;
}