动态规划背包类型

背包类型有三种:

  1. 01背包模型:有N种物品和一个容量为V的背包,每种物品只有一种。第i种物品的体积是v[i],价值是w[i]。求不超过体积且价值最大。
  2. 完全背包模型:有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是v[i],价值是w[i]。求不超过体积且价值最大。
  3. 多重背包模型:有N种物品和一个容量为V的背包,每种物品都有有限件可用。第i种物品的体积是v[i],价值是w[i],最多可用件数为n[i]。求不超过体积且价值最大。

其中,01和多重为了保证,i层由i-1层递推过来,j(背包限制)是从大到小遍历的。
原因:从较小体积→较大体积有可能出错

想象循环到第i行,从左向右更新j的状态,当更新某个j的时候用到了j-w,j-w其实已经在第i行被更新过了(因为顺序是从左往右更新),但我们需要的是第i-1行j-w的状态。

总而言之,我们需要的j是第i层的,而不是i-1层的j,因此需要逆序。

代码逻辑:

  1. 遍历从前i个的方案——第一层for
  2. 对于每一个i,遍历每一种体积(此处应有限制,j必须不小于i-1层的体积且不超过最大体积)——第二层for
    (3. 对于每一种2.,遍历选取多少个的可能)

多重一维优化(节选自采药P1048)

for (int i = 0; i < n; i ++ )
    {
        int v, w;
        cin >> v >> w;
        for (int j = m; j >= v; j -- )
            f[j] = max(f[j], f[j - v] + w);
    }

01背包一维优化

for(int i = 1; i <= n; i++) 
    for(int j = m; j >= 0; j--)
    {
            f[i][j] = f[i - 1][j];  // 优化前
            f[j] = f[j];            // 优化后,该行自动成立,可省略。
       if(j >= v[i])    
            f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);  // 优化前
            f[j] = max(f[j], f[j - v[i]] + w[i]);                   // 优化后
    }   

采药P1048

01背包问题,板子。
这里提供优化和没有优化的代码

import java.io.*;
public class P1048 {
	static int T=1000+10;
	static int M=100+10;
	static int t,m;
	
	static int f[][]=new int[M][T];
	static int ff[]=new int[T];
	static int time[]=new int[M];
	static int w[]=new int[M];
	
	public static void main(String args[]) throws IOException{
		BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
		
		String init[]=in.readLine().split(" ");
		t=Integer.parseInt(init[0]);
		m=Integer.parseInt(init[1]);
		
		for(int i=1;i<=m;i++) {//*
			String data[]=in.readLine().split(" ");
			time[i]=Integer.parseInt(data[0]);
			w[i]=Integer.parseInt(data[1]);
			for(int j=t;j>=time[i];j--) {
				ff[j]=Math.max(ff[j],ff[j-time[i]]+w[i]);
			}
		}
		System.out.println(ff[t]);
		
		for(int i=1;i<=m;i++) {
			for(int j=0;j<=t;j++) {
				f[i][j]=f[i-1][j];
				if (j >= time[i]) f[i][j] = Math.max(f[i][j], f[i - 1][j - time[i]] + w[i]);//选
			}
		}
		
		System.out.println(f[m][t]);
	}
}

装箱问题P1049

01背包问题,板子题。
本题特殊点:需要转换问题,将“求箱子剩余空间最小”→“装入物品体积最大”。

import java.util.*;
public class P1049 {
	static int V=20000+10;
	static int N=30+10;
	
	static int boxV,n;
	static int f[]=new int[N];
	static int v[]=new int[N];
	public static void main(String args[]){
		Scanner sc=new Scanner(System.in);
		boxV=sc.nextInt();
		n=sc.nextInt();
		for(int i=1;i<=n;i++) {
			int v=sc.nextInt();
			for(int j=boxV;j>=v;j--) {
				f[j]=Math.max(f[j],f[j-v]+v);
			}
		}
		

//		for(int i=1;i<=n;i++) {
//			f[i]=f[i-1];
//			
//			if(f[i-1]-v[i]>=0) f[i]=Math.min(f[i],f[i-1]-v[i]);
//		}
//		
		System.out.println(boxV-f[boxV]);
	}

}

摆花P1077

多重背包问题。
初始化:从前0种中选,自然只有1种方案


import java.util.*;
public class P1077 {
	static int n,m;
	static int N=100+10;
	static int f[]=new int[N];
	static int mod=1000007;
	public static void main(String args[]) {
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		m=sc.nextInt();
		
		f[0]=1;
		for(int i=0;i<n;i++) {
			int a=sc.nextInt();
			for(int j=m;j>=0;j--) {//遍历容量,遍历摆多少个
				for(int k=1;k<=j && k<=a;k++) {//遍历选i-1号花盆的情况
					f[j]=(f[j]+f[j-k])%mod;
				}
			}
		}
		
		System.out.println(f[m]);
	}
}

买书AcWing1023

将个数遍历到小于等于j
代码具体查看:https://www.acwing.com/solution/content/52967/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值