背包九讲 11题

2024-03-20 16:58
文章标签 背包 九讲

本文主要是介绍背包九讲 11题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

聚聚视频讲的太好了

前六讲 最后三讲

 

题目全在这了

 01背包问题

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=1e3+5;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int dp[N],n,m;
int main(){std::ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=1,v,w;i<=n;++i){cin>>v>>w;for(int j=m;j>=v;--j) dp[j]=max(dp[j],dp[j-v]+w);}cout<<dp[m]<<endl;return 0;
}

完全背包

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=1e3+5;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int dp[N],n,m;
int main(){std::ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=1,v,w;i<=n;++i){cin>>v>>w;for(int j=v;j<=m;++j) dp[j]=max(dp[j],dp[j-v]+w);}cout<<dp[m]<<endl;return 0;
}

多重背包问题 I

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=105;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int dp[N],n,m;
int main(){std::ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=1,v,w,s;i<=n;++i){cin>>v>>w>>s;for(int j=m;j>=v;--j){for(int k=0;k<=s && k*v<=j;++k){dp[j]=max(dp[j],dp[j-k*v]+k*w);}}}cout<<dp[m]<<endl;return 0;
}

多重背包问题 II

二进制拆分优化,然后作为01背包来考虑即可,将s拆成2进制表示,最后多的那个部分单独拿出来。 

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=2e3+5;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
struct node{int v,w;
};
vector<node> a;
int n,m,dp[N];
int main(){std::ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=1,v,w,s;i<=n;++i){cin>>v>>w>>s;for(int k=1;k<=s;k*=2){a.pb({v*k,w*k});s-=k;}if(s) a.pb({v*s,w*s});} for(auto it:a){int v=it.v,w=it.w;for(int j=m;j>=v;--j) dp[j]=max(dp[j],dp[j-v]+w);}cout<<dp[m]<<endl; return 0;
}

多重背包问题 III

单调队列优化,对于一个体积为v的物品,我们考虑到他的更新,将体积%v的值进行分组,一个组之间才会有递推关系,而不同的组之间是不会有更新和递推关系的。考虑对于一个dp[j] 是从上一层dp[j-v]+w,dp[j-2*v]+2*w…….更新来,那对于dp[j+v]就是从上一层dp[j]+w,dp[j-v]+2*w…..更新而来,其实就是对于dp[j],dp[j+v]就是平移的一格,然后总体+w;但是原来数的大小关系并没有发生改变,所以这里用单调队列维护即可,只是加的x*w发生了改变,这个我们可以通过计算与j差几个v,就可以得出了嘛。

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=2e5+5;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int n,m,dp[N][2],q[N];
int main(){std::ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;bool fg=0;int tt=-1,hh=0; for(int i=1,v,w,s;i<=n;++i){cin>>v>>w>>s;for(int j=0;j<v;++j){//将体积按%v的值进行分类 tt=-1,hh=0;for(int k=j;k<=m;k+=v){dp[k][fg]=dp[k][fg^1];while(hh<=tt && k-s*v>q[hh]) hh++;if(hh<=tt) dp[k][fg]=max(dp[k][fg],dp[q[hh]][fg^1]+(k-q[hh])/v*w);while(hh<=tt && dp[q[tt]][fg^1]-(q[tt]-j)/v*w <= dp[k][fg^1]-(k-j)/v*w) tt--; q[++tt]=k;}	}fg^=1;}cout<<dp[m][fg^1]<<endl;return 0;
}

混合背包问题

即包含了01背包,完全背包和多重背包,这里可以将多重背包拆分成01背包,然后我们只需要考虑01背包和完全背包,这里两个注意循环的方向即可。

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=1e3+5;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int dp[N],n,m;
struct node{int type,v,w;
};
vector<node> a;
int main(){std::ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=1,v,w,s;i<=n;++i){cin>>v>>w>>s;if(s==-1) a.pb({-1,v,w});//01背包 else if(s==0) a.pb({0,v,w});//多重背包 else{//完全背包拆成01背包 for(int k=1;k<=s;k*=2){a.pb({-1,v*k,w*k});s-=k; } if(s) a.pb({-1,v*s,w*s});}}int v,w;for(auto it:a){v=it.v,w=it.w;if(it.type==-1){for(int i=m;i>=v;--i) dp[i]=max(dp[i],dp[i-v]+w);}else{for(int i=v;i<=m;++i) dp[i]=max(dp[i],dp[i-v]+w);}} cout<<dp[m]<<endl;return 0;
}

二维费用的背包问题

多了一维重量,这里直接考虑多循环一层重量即可,01背包从大到小进行更新即可。

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=1e3+5;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int dp[N][N],n,V,M;
int main(){std::ios::sync_with_stdio(0);cin.tie(0);cin>>n>>V>>M;for(int i=1,v,m,w;i<=n;++i){cin>>v>>m>>w;for(int j=V;j>=v;--j){for(int k=M;k>=m;--k){dp[j][k]=max(dp[j][k],dp[j-v][k-m]+w);}} }cout<<dp[V][M]<<endl;return 0;
}

分组背包问题

多一重循环,来判断选这一组里的哪一个

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=1e2+5;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int n,m,v[N],w[N],dp[N];
int main(){std::ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=1,s;i<=n;++i){cin>>s;for(int j=1;j<=s;++j) cin>>v[j]>>w[j];for(int j=m;j>=0;--j){for(int k=1;k<=s;++k){if(j>=v[k]) dp[j]=max(dp[j],dp[j-v[k]]+w[k]);}}}cout<<dp[m]<<endl;return 0;
}

有依赖的背包问题

dp[i][j]:当选i为节点,空间不大于j的最大值

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=1e2+5;
//il int Add(ll &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(ll &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int dp[N][N];//dp[i][j]:当选i为节点,空间不大于j的最大值
int n,m,v[N],w[N],root; 
vector<int> G[N];
il void dfs(int u){for(auto son:G[u]){dfs(son);for(int j=m-v[u];j>=0;--j){//给u空出v[u]空间,剩下的分给儿子 for(int k=0;k<=j;++k){dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[son][k]);}}}for(int j=m;j>=v[u];--j) dp[u][j]=dp[u][j-v[u]]+w[u];for(int j=v[u]-1;j>=0;--j) dp[u][j]=0;
}
int main(){std::ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=1,np;i<=n;++i){cin>>v[i]>>w[i]>>np;if(np==-1) root=i;else G[np].pb(i);}dfs(root);cout<<dp[root][m]<<endl;return 0;
}

背包问题求方案数

这里初始化不能随便的默认为0了,因为这里需要更新方案数,前面的dp[i]表示体积不大于i的最大价值,(这和全部初始化为0有关,因为如果当空间为k时取得最大价值,因为我们将dp[m-k]初始化为0,所以也可以得到最值,但实际空间不为m)这样的话不利于更新方案数。现在初始话只将dp[0]定义为0,其他的定义为-infdp[i]表示空间恰好为i时的最大价值,这样是符合实际情况的,最后的mx是要扫一遍数组的,因为最大价值并不一定在最大空间取得。

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int mod=1e9+7;
const int N=1e3+5; 
il int Add(int &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(int &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int dp[N],num[N];
//dp[i]:体积为i时的最大价值,num[i]:满足体积为i最大价值的方案数 
int n,m;
int main(){std::ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;num[0]=1;for(int i=1;i<=m;++i) dp[i]=-inf;for(int i=1,v,w;i<=n;++i){cin>>v>>w;for(int j=m;j>=v;--j){int mx,mxnum=0;mx=max(dp[j],dp[j-v]+w);if(mx==dp[j]) Add(mxnum,num[j]);if(mx==dp[j-v]+w) Add(mxnum,num[j-v]);dp[j]=mx,num[j]=mxnum;}}int ans=-inf,all=0;for(int j=0;j<=m;++j) ans=max(ans,dp[j]);for(int j=0;j<=m;++j){if(dp[j]==ans) Add(all,num[j]);}cout<<all<<endl;return 0;
}

背包问题求具体方案

因为题目要求字典序,所以i从大到小着来,然后从1到n从小到大贪心的考虑。视频中代码少加了一个nv-v[i]的判断。

#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=1e3+5;
//il int Add(int &x,ll y) {return x=x+y>=mod?x+y-mod:x+y;}
//il int Mul(int &x,ll y) {return x=x*y>=mod?x*y%mod:x*y;}
int n,m,dp[N][N],v[N],w[N];int main(){std::ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=1;i<=n;++i) cin>>v[i]>>w[i];//从后往前更新 for(int i=n;i>=1;--i){for(int j=0;j<=m;++j){if(j>=v[i]) dp[i][j]=max(dp[i+1][j],dp[i+1][j-v[i]]+w[i]);else dp[i][j]=dp[i+1][j];}}int nv=m;for(int i=1;i<=n;++i){if(nv-v[i]>=0 && dp[i][nv]==dp[i+1][nv-v[i]]+w[i]){cout<<i<<" ";nv-=v[i];}}return 0;
}

 

 

这篇关于背包九讲 11题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/830139

相关文章

poj2576(二维背包)

题意:n个人分成两组,两组人数只差小于1 , 并且体重只差最小 对于人数要求恰好装满,对于体重要求尽量多,一开始没做出来,看了下解题,按照自己的感觉写,然后a了 状态转移方程:dp[i][j] = max(dp[i][j],dp[i-1][j-c[k]]+c[k]);其中i表示人数,j表示背包容量,k表示输入的体重的 代码如下: #include<iostream>#include<

hdu2159(二维背包)

这是我的第一道二维背包题,没想到自己一下子就A了,但是代码写的比较乱,下面的代码是我有重新修改的 状态转移:dp[i][j] = max(dp[i][j], dp[i-1][j-c[z]]+v[z]); 其中dp[i][j]表示,打了i个怪物,消耗j的耐力值,所得到的最大经验值 代码如下: #include<iostream>#include<algorithm>#include<

csu(背包的变形题)

题目链接 这是一道背包的变形题目。好题呀 题意:给n个怪物,m个人,每个人的魔法消耗和魔法伤害不同,求打死所有怪物所需的魔法 #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<queue>#include<set>//#include<u>#include<map

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

uva 10130 简单背包

题意: 背包和 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>

HDU 2159 二维完全背包

FATE 最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在不停的杀怪做任务。久而久之xhd开始对杀怪产生的厌恶感,但又不得不通过杀怪来升完这最后一级。现在的问题是,xhd升掉最后一级还需n的经验值,xhd还留有m的忍耐度,每杀一个怪xhd会得到相应的经验,并减掉相应的忍耐度。当忍耐度降到0或者0以下时,xhd就不会玩这游戏。xhd还说了他最多只杀s只怪。请问他能

多重背包转换成0-1背包

http://acm.hdu.edu.cn/showproblem.php?pid=2191 多重背包特点: 一种物品有C个(既不是固定的1个,也不是无数个) 优化的方法: 运用神奇的二进制,进行物品拆分,转化成01背包 物品拆分,把13个相同的物品分成4组(1,2,4,6) 用这4组可以组成任意一个1~13之间的数! 原理:一个数总可以用2^

POJ1384背包

体积V的包包 n种硬币,体积weight价值value 求把包包恰好装满最小的价值 import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.math.BigInteger;imp