背包
- 背包作为线性DP的一种,由于其状态及转移的较特殊性、可拓展性以及广泛的应用,通常被单独列为DP的一种题型
P1757 通天之分组背包
-
此题为分组背包模板题。
-
“分组”的常见处理方法是将枚举组数、背包大小以及组内物品分开依次枚举,拆分成01背包。
通过使每一组中的每一种物品都由上一组的DP值转移过来,就可以实现每一组只能选一个物品了。
需要注意的是枚举的背包大小仍然是倒序的,否则就成完全背包了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e3+7;
const int M=1e2+7;
int m,n,t,a[N],b[N],c[N],tmp[N][M],f[N],cnt[N];
vector <int> q[N];
signed main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>m>>n;
for(int i=1;i<=n;i++)
cin>>a[i]>>b[i]>>c[i],t=max(c[i],t),cnt[c[i]]++,tmp[c[i]][cnt[c[i]]]=i;
for(int i=1;i<=t;i++)
for(int j=m;j>=0;j--)
for(int k=1;k<=cnt[i];k++)
if(j-a[tmp[i][k]]>=0)
f[j]=max(f[j],f[j-a[tmp[i][k]]]+b[tmp[i][k]]);
cout<<f[m];
return 0;
}
P2340 [USACO03FALL] Cow Exhibition G
思路
-
这种每种物品都只能选一次同时贡献固定的问题,我们就可以考虑将其转化为01背包。
-
对于这道题,我们将s看做代价,f看成收益,直接做01背包最后统计答案时直接重新加上s的贡献就可以了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=800005;
struct node
{
int v,w;
}a[N];
int n,f[N],up,down;
bool cmp(node x,node y){return x.v>y.v;}
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n;memset(f,-0x3f,sizeof(f));up=N-5;f[up/2]=0;
for(int i=1;i<=n;i++) {cin>>a[i].v>>a[i].w;}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
if(a[i].v<0) for(int j=0;j<=up+a[i].v;j++) f[j]=max(f[j],f[j-a[i].v]+a[i].w);
else for(int j=up;j>=a[i].v;j--) f[j]=max(f[j],f[j-a[i].v]+a[i].w);
}
int ans=0;
for(int i=up/2;i<=up;i++) if(f[i]>=0)ans=max(ans,f[i]+i-up/2);
cout<<max(0,ans);
return 0;
}
P1064 [NOIP2006 提高组] 金明的预算方案
-
此题为依赖背包的模板题。
-
“依赖”听起来是个比较高深的限制条件。但是由于题目的数据范围极小
(\(1 \leq n \leq 3.2 \times 10^4\),\(1 \leq m \leq 60\),\(0 \leq v_i \leq 10^4\),\(1 \leq p_i \leq 5\),\(0 \leq q_i \leq m\),答案不超过 \(2 \times 10^5\))
因此可以直接做。 -
具体来说就是先将所有“主件”以及所依赖与它的“附件”预处理出来。
对于每一组,我们就去枚举
- 只选主件 2.选主件以及第一件 3.选主件以及第二件
这三种情况,方程是比较显然的,与01背包等同。
-
但是我不知道有没有不是这样过于暴力的做法,因为其复杂度是 \(O(mn\times w)\) 的,设最多允许有 \(k\) 个附件,则其中 \(w\) 为 \(\sum_{i=1}^{k} C_k^i=2^k-1\)
-
也就是说这个算法几乎无法扩展,\(k\) 稍微大一点就要爆,因此依赖背包的数据范围和应用一般都不是很广。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=4005;
int n,m,tot[N],f[N],v[N],p[N];
vector <int> q[N];
bool sign[N];
signed main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;n/=10;
for(int i=1,bel;i<=m;i++){cin>>v[i]>>p[i]>>bel;v[i]/=10;if(bel) q[bel].push_back(i),tot[bel]++,sign[i]=1;}
for(int i=1;i<=m;i++)
{
if(sign[i]) continue;
for(int j=n;j>=0;j--)
{
int a=0,b=0;if(tot[i]>=1) a=q[i][0];if(tot[i]>=2) b=q[i][1];
if(j-v[i]>=0)f[j]=max(f[j],f[j-v[i]]+v[i]*p[i]);
if(a)if(j-v[i]-v[a]>=0)f[j]=max(f[j],f[j-v[i]-v[a]]+v[i]*p[i]+v[a]*p[a]);
if(b)if(j-v[i]-v[b]>=0)f[j]=max(f[j],f[j-v[i]-v[b]]+v[i]*p[i]+v[b]*p[b]);
if(a&&b)if(j-v[i]-v[a]-v[b]>=0)
f[j]=max(f[j],f[j-v[i]-v[a]-v[b]]+v[i]*p[i]+v[a]*p[a]+v[b]*p[b]);
}
}
cout<<f[n]*10;
return 0;
}
P1941 [NOIP2014 提高组] 飞扬的小鸟
思路
-
由于每个格子的信息并不一样,不能用神秘方法乱搞,因此显然是一道DP题,设状态 \(f_{i,j}\) 表示在第 \(i\) 列第 \(j\) 行所需要的最少按键次数。考虑如何去转移。
-
由题有两种转移方式:1. 自然下落,不消耗步数 2. 向上走任意多步,要消耗对应的步数。
“任意多步”是一个较为强的条件,考虑完全背包去转移。而对于自然下落,就容易顺着想到01背包。 -
想到背包就很好做了,状态转移较为显然。但注意一下一个小细节:可以一直顶格飞,意思就是因为高度不能超过m,就会出现样例解释2中的情况。
-
因此 \(j=m\) 时的转移需要单独考虑,除了上述的正常转移之外,也可以由上一步中高度小于上升步数的点转移而来。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+7;
const int inf=1e9+7;
int n,m,k,h[N],l[N],up[N],down[N],f[N][2002],cnt=0;
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m>>k;memset(f,0x3f,sizeof(f));for(int i=1;i<=m;i++) f[0][i]=0;
for(int i=0;i<=n-1;i++) cin>>up[i]>>down[i];
for(int i=1,x,ll,hh;i<=k;i++) cin>>x>>ll>>hh,h[x]=hh,l[x]=ll;
for(int i=1;i<=n;i++)
{
for(int j=up[i-1]+1;j<=up[i-1]+m;j++) f[i][j]=min(f[i-1][j-up[i-1]]+1,f[i][j-up[i-1]]+1);
for(int j=m;j<=up[i-1]+m;j++) f[i][m]=min(f[i][m],f[i][j]);
for(int j=1;j<=m-down[i-1];j++) f[i][j]=min(f[i][j],f[i-1][j+down[i-1]]);
if(h[i]!=0||l[i]!=0)
{
for(int j=1;j<=l[i];j++) f[i][j]=inf;
for(int j=h[i];j<=m;j++) f[i][j]=inf;
bool sign=0;
for(int j=1;j<=m;j++) if(f[i][j]<=10000000) {sign=1;break;}
if(!sign) {cout<<"0\n"<<cnt;return 0;}
cnt++;
}
}
int ans=inf;
for(int i=1;i<=m;i++) ans=min(ans,f[n][i]);
cout<<"1\n"<<ans;
return 0;
}

浙公网安备 33010602011771号