动态规划:背包问题模板代码汇总

说明:根据acwing算法提高课和算法基础课整理,代码根据y总的稍加修改。

1.0-1背包问题

问题模型描述:

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。

第 i 件物品的体积是vi,价值是 wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。

模板题:2. 01背包问题 - AcWing题库
代码(空间优化版):

#include
using namespace std;
const int N=1010;
int f[N];
int main()
{
	int n,m;
	cin>>n>>m; //数量和总体积 
	for(int i=0;i>v>>w;
		for(int j=m;j>=v;--j) f[j]=max(f[j],f[j-v]+w);
	}
	cout<

 2.完全背包问题

问题模型描述:0-1背包问题的基础上,每一个物品可以无限选用。

模板题:3. 完全背包问题 - AcWing题库

代码(优化到O(n^2),空间一维):

#include
using namespace std;
const int N=1010;
int f[N];
int main()
{
	int n,m;
	cin>>n>>m; //数量和总体积 
	for(int i=0;i>v>>w;
		for(int j=v;j<=m;++j) f[j]=max(f[j],f[j-v]+w);
	}
	cout<

3.分组背包问题 

问题模型描述:

有 N 组物品和一个容量是 V 的背包。每组物品有若干个,同一组内的物品最多只能选一个。

求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。

模板题:9. 分组背包问题 - AcWing题库

代码:

#include
using namespace std;
const int N=110;
int f[N],v[N][N],w[N][N],s[N];
int main()
{
	int n,m;
	cin>>n>>m; //数量和总体积 
	for(int i=1;i<=n;++i){ 
		cin>>s[i]; //第i类的个数 
		for(int j=1;j<=s[i];++j) cin>>v[i][j]>>w[i][j]; 
	}
	for(int i=1;i<=n;++i)
	for(int j=m;j>=0;--j)
	for(int k=1;k<=s[i];++k)
	if(v[i][k]<=j) f[j]=max(f[j],f[j-v[i][k]]+w[i][k]);
	cout<

4.最长公共上升子序列问题

这个不算背包模型,算是区间dp,朴素做法复杂度是O(n^3),这里贴上O(n^2)复杂度的代码。

问题模型描述:两个数列 A 和 B,如果它们都包含一段位置不一定连续的数,且数值是严格递增的,那么称这一段数是两个数列的公共上升子序列,而所有的公共上升子序列中最长的就是最长公共上升子序列。

模板题:272. 最长公共上升子序列 - AcWing题库

代码(O(n^2)):

#include
using namespace std;
const int N=3010;
int n,a[N],b[N],f[N][N];
int main()
{
    cin>>n;
    for(int i=1;i<=n;++i) cin>>a[i];
    for(int i=1;i<=n;++i) cin>>b[i];
    for(int i=1;i<=n;++i){
        int maxv=1;
        for(int j=1;j<=n;++j){
            f[i][j]=f[i-1][j];
            if(a[i]==b[j]) f[i][j]=max(f[i][j],maxv);
            if(b[j]

5.背包问题求方案数

问题模型描述:0-1背包问题的基础上,最优选法的方案数。

模板题:11. 背包问题求方案数 - AcWing题库

代码:

#include
using namespace std;
const int N=1010,mod=1e9+7;
int f[N],g[N];
int main()
{
    int n,m;
    cin>>n>>m;
    g[0]=1;
    for(int i=0;i>v>>w;
        for(int j=m;j>=v;--j){
            int mav=max(f[j],f[j-v]+w),cnt=0;
            if(mav==f[j]) cnt+=g[j];
            if(mav==f[j-v]+w) cnt+=g[j-v];
            cnt%=mod;
            g[j]=cnt;
            f[j]=mav;
        }
    }
    int res=0,ans=0;
    for(int i=0;i

6.有依赖的背包问题。

问题模型描述:有 N 个物品和一个容量是 V 的背包。物品之间具有依赖关系,且依赖关系组成一棵树的形状。如果选择一个物品,则必须选择它的父节点。

模板题:10. 有依赖的背包问题 - AcWing题库

状态表示:f[u][m]:以u为根节点的子树,在代价不超过m时产生的最大价值。

#include
using namespace std;
const int N=110;
int h[N],ne[N],e[N],idx,v[N],w[N],f[N][N];
int n,m;
void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u)
{
	for(int i=h[u];~i;i=ne[i]){
		int son=e[i];
		dfs(son);
		for(int j=m-v[u];j>=0;--j)
		for(int k=0;k<=j;++k)
		f[u][j]=max(f[u][j],f[u][j-k]+f[son][k]);
	}
	for(int i=m;i>=v[u];--i) f[u][i]=f[u][i-v[u]]+w[u];
	for(int i=0;i>n>>m;
	memset(h,-1,sizeof(h));
	int r;
	for(int i=1;i<=n;++i){
		int p;
		cin>>v[i]>>w[i]>>p;
		if(p==-1) r=i;
		else add(p,i);
	}
	dfs(r);
	cout<

 7.多重背包问题

问题模型描述:0-1背包问题的基础上,第i个物品最多选择si件。

模板题:5. 多重背包问题 II - AcWing题库

代码(二进制优化版):

#include
using namespace std;
const int M=2010,N=25000;
int v[N],w[N],f[M];
int main()
{
    int n,m;
    cin>>n>>m;
    int cnt=0;
    for(int i=1;i<=n;++i){
    	int a,b,s;
    	cin>>a>>b>>s;
    	int k=1;
    	while(k<=s){
    		++cnt;
    		v[cnt]=a*k,w[cnt]=b*k;
    		s-=k;
    		k<<=1;
		}
		if(s>0){
			++cnt;
			v[cnt]=a*s,w[cnt]=b*s;
		}
	}
	n=cnt;
	for(int i=1;i<=n;++i)
	for(int j=m;j>=v[i];--j)
	f[j]=max(f[j],f[j-v[i]]+w[i]);
	cout<

滑动窗口优化版:

#include
using namespace std;
const int N=20010;
int f[N],g[N],q[N];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i>v>>w>>s;
        memcpy(g,f,sizeof(f)); //存上一层状态
        for(int j=0;j

 

 8.组合背包问题

问题模型描述:有 N 种物品和一个容量是 V 的背包。

物品一共有三类:

  • 第一类物品只能用1次(01背包);
  • 第二类物品可以用无限次(完全背包);
  • 第三类物品最多只能用 si 次(多重背包);

模板题:7. 混合背包问题 - AcWing题库

代码:

#include
using namespace std;
const int N=1010;
int n,m;
int f[N];
int main()
{
    cin>>n>>m;
    for(int i=0;i>v>>w>>s;
        if(s==0) //完全背包
        for(int j=v;j<=m;++j) f[j]=max(f[j],f[j-v]+w);
        else{
            if(s==-1) s=1; //01背包相当于个数为1的多重背包
            for(int k=1;k<=s;k*=2){
                for(int j=m;j>=k*v;--j) f[j]=max(f[j],f[j-k*v]+k*w);
                s-=k;
            }
            if(s) for(int j=m;j>=s*v;--j) f[j]=max(f[j],f[j-s*v]+s*w);
        }
    }
    cout<

 

你可能感兴趣的:(动态规划,算法,c++)