背包问题
还有一个依赖背包暂时没学,基础dp应该用不到吧……
1.普通背包
已知 n n n件物品的体积和价值,每一件最多用一次,总体积不能超过 v o l vol vol,问最大价值
核心代码: d p [ v o l ] dp[vol] dp[vol]即为答案
for (int i=1;i<=n;i++)
{
for (int j=vol;j>=p[i].w;j--)
{
dp[j]=max(dp[j],dp[j-p[i].w]+p[i].val);
}
}
2.完全背包
已知 n n n件物品的体积和价值,每一件可以随便用,总体积不能超过 v o l vol vol,问最大价值
核心代码: d p [ v o l ] dp[vol] dp[vol]即为答案
for (int i=1;i<=n;i++)
{
for (int j=p[i].w;j<=vol;j++)
{
dp[j]=max(dp[j],dp[j-p[i].w]+p[i].val);
}
}
3.多重背包
已知 n n n件物品的体积和价值和数量,总体积不能超过 v o l vol vol,问最大价值
核心代码: d p [ v o l ] dp[vol] dp[vol]即为答案
for (int i=1;i<=n;i++)
{
for (int j=0;j<p[i].num;j++)
{
for (int k=vol;k>=p[i].w;k--)
{
dp[k]=max(dp[k],dp[k-p[i].w]+p[i].val);
}
}
}
4.分组背包
已知物品的价值和体积,分成 K K K个组,每个组只能最多取一件,总体积不能超过 v o l vol vol,问最大价值
核心代码: d p [ v o l ] dp[vol] dp[vol]即为答案
for (int i=1;i<=K;i++)//每个组
{
for (int k=vol;k>=0;k--)
{
for (int j=0;j<group[i].size();j++)
//每个组里面每一个物品,用vector或者数组存
{
int x=group[i][j];
if (k>=w[x])
{
dp[k]=max(dp[k],dp[k-w[x]]+val[x]);
}
}
}
}
例题1
HDU1171
其实每一个多重背包也可以看成是普通背包来做,把具有多个数量的物品拆成很多个单一物体就可以了,这个思想叫啥也说不上来
大致题意:一共有N组数据,包含设备的价值和数量,把这些设备均分,使得分成的两堆价值差异尽量小
分析:先求出设备总价值量 s u m = ∑ ( w [ i ] ∗ n u m [ i ] ) sum=\sum(w[i]*num[i]) sum=∑(w[i]∗num[i]),然后在体积为 s u m / 2 sum/2 sum/2的背包中求就可以了
做法1:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x<b;x++)
#define mem(a,x) memset(a,x,sizeof a)
using namespace std;
const int maxn=2e6+7;
int dp[maxn],n,x,y;
vector<int >v;
int main()
{
while(~scanf("%d",&n)&&n>-1)
{
int sum=0;
mem(dp,0);
v.clear();
rep(i,1,n)
{
scanf("%d%d",&x,&y);
sum+=x*y;
while(y--)v.pb(x);
}
int sum1=sum/2;
for (int i=0;i<v.size();i++)
{
for (int j=sum1;j>=v[i];j--)
{
dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
}
}
cout<<max(dp[sum1],sum-dp[sum1])<<" "<<min(dp[sum1],sum-dp[sum1])<<endl;
}
return 0;
}
做法2:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x<b;x++)
#define mem(a,x) memset(a,x,sizeof a)
using namespace std;
const int maxn=2e6+7;
int dp[maxn],n,x,y;
struct node
{
int x;
int num;
} p[maxn];
int main()
{
while(~scanf("%d",&n)&&n>-1)
{
mem(dp,0);
int sum=0;
rep(i,1,n)
{
scanf("%d%d",&x,&y);
p[i].x=x;
p[i].num=y;
sum+=x*y;
}
for (int i=1; i<=n; i++)
{
for (int j=0; j<p[i].num; j++)
{
for (int k=sum/2; k>=p[i].x; k--)
{
dp[k]=max(dp[k],dp[k-p[i].x]+p[i].x);
}
}
}
cout<<max(dp[sum/2],sum-dp[sum/2])<<" "<<min(dp[sum/2],sum-dp[sum/2])<<endl;
}
return 0;
}
例题2
P1164 小A点菜
虽然也是背包问题,但需要进一步的理解
大致题意:给出N个菜,兜里有M块钱,问有多少种买菜方案,使得钱刚好花完。
根据题目的数据,可以枚举在位置i剩余 x ( 1 ≤ x ≤ m ) x(1\leq x \leq m) x(1≤x≤m)块钱的情形,买或者不买为转移条件
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
#define rep(x,a,b) for (int x=a;x<=b;x++)
#define repp(x,a,b) for (int x=a;x<b;x++)
#define W(x) printf("%d\n",x)
#define WW(x) printf("%lld\n",x)
#define pi 3.14159265358979323846
#define mem(a,x) memset(a,x,sizeof a)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int maxn=1e4+7;
const int INF=1e9;
const ll INFF=1e18;
ll dp[101][maxn],a[maxn],n,m,ans=0;
int main()
{
scanf("%lld%lld",&n,&m);
rep(i,1,n)scanf("%lld",&a[i]);
mem(dp,0);
dp[1][m]=1;
if (m>=a[1])dp[1][m-a[1]]=1;
rep(i,2,n)
{
rep(j,1,m)
{
if (j>=a[i])dp[i][j-a[i]]+=dp[i-1][j];
dp[i][j]+=dp[i-1][j];
}
}
rep(i,1,n)ans+=dp[i][0];
WW(ans);
}
例题3
P1616 疯狂的采药
多重背包模板题