2024-02-05(背包问题)

背包问题

(1)01背包问题

2. 01背包问题 - AcWing题库

二维

import java.util.*;

public class Main{
    public static void main(String[] args){
        int N = 1010;
        int[][] f = new int[N][N];//表示最大价值
        int[] w = new int[N];//每件物品的价值
        int[] v = new int[N];//每件物品的体积
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();//物品总的数量
        int m = sc.nextInt();//背包的容积
        for(int i = 1; i <= n; i ++){
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
        }
        
        for(int i = 1; i <= n; i ++){
            for(int j = 0; j <= m; j ++){
                f[i][j] = f[i - 1][j];//集合划分的左边
                if(v[i] <= j) f[i][j] = Math.max(f[i][j], f[i - 1][j - v[i]] + w[i]);//当第i件物品的体积小于j时,才有左边右边取最大值
            }
        }
        
        System.out.print(f[n][m]);
    }
}

 一维优化

import java.util.*;

public class Main{
    public static void main(String[] args){
        int N = 1010;
        int[] f = new int[N];//表示最大价值
        int[] w = new int[N];//每件物品的价值
        int[] v = new int[N];//每件物品的体积
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();//物品总的数量
        int m = sc.nextInt();//背包的容积
        for(int i = 1; i <= n; i ++){
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
        }
        
        for(int i = 1; i <= n; i ++){
            for(int j = m; j >= v[i]; j --){//这里原来j是从0开始的,但是由于当v[i] <= j就没有意义了,所以直接从v[i]开始
                f[j] = Math.max(f[j], f[j - v[i]] + w[i]);
            }
        }
        
        System.out.print(f[m]);
    }
}

 (2)完全背包问题

3. 完全背包问题 - AcWing题库

二维(三重循环)

import java.util.*;
import java.io.*;

public class Main{
    public static void main(String[] args)throws IOException{
        int N = 1010;
        int[] v = new int[N];
        int[] w = new int[N];
        int[][] f = new int[N][N];
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        String[] str = br.readLine().split(" ");
        int n = Integer.parseInt(str[0]);
        int m = Integer.parseInt(str[1]);
        for(int i = 1; i <= n; i ++){
            String[] arr = br.readLine().split(" ");
            v[i] = Integer.parseInt(arr[0]);
            w[i] = Integer.parseInt(arr[1]);
        }
        
        for(int i = 1; i <= n; i ++){
            for(int j = 0; j <= m; j ++){
               for(int k = 0; k * v[i] <= j; k ++){
                   //和01背包问题的主要区别在这里
                    f[i][j] = Math.max(f[i][j], f[i - 1][j - v[i] * k] + w[i] * k);
               }
            }
        }
        
        System.out.print(f[n][m]);
    }
}

二维(两重循环) 

import java.util.*;
import java.io.*;

public class Main{
    public static void main(String[] args)throws IOException{
        int N = 1010;
        int[] v = new int[N];
        int[] w = new int[N];
        int[][] f = new int[N][N];
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        String[] str = br.readLine().split(" ");
        int n = Integer.parseInt(str[0]);
        int m = Integer.parseInt(str[1]);
        for(int i = 1; i <= n; i ++){
            String[] arr = br.readLine().split(" ");
            v[i] = Integer.parseInt(arr[0]);
            w[i] = Integer.parseInt(arr[1]);
        }
        
        for(int i = 1; i <= n; i ++){
            for(int j = 0; j <= m; j ++){
               f[i][j] = f[i - 1][j];
                //和01背包问题的主要区别在这里
               if(v[i] <= j) f[i][j] = Math.max(f[i][j], f[i][j - v[i]] + w[i]);
            }
        }
        
        System.out.print(f[n][m]);
    }
}

  一维优化

import java.util.*;
import java.io.*;

public class Main{
    public static void main(String[] args)throws IOException{
        int N = 1010;
        int[] v = new int[N];
        int[] w = new int[N];
        int[] f = new int[N];
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        String[] str = br.readLine().split(" ");
        int n = Integer.parseInt(str[0]);
        int m = Integer.parseInt(str[1]);
        for(int i = 1; i <= n; i ++){
            String[] arr = br.readLine().split(" ");
            v[i] = Integer.parseInt(arr[0]);
            w[i] = Integer.parseInt(arr[1]);
        }
        
        for(int i = 1; i <= n; i ++){
            for(int j = v[i]; j <= m; j ++){
            //这里的j不需要逆序输入
               f[j] = Math.max(f[j], f[j - v[i]] + w[i]);
            }
        }
        
        System.out.print(f[m]);
    }
}

(3)多重背包问题

4. 多重背包问题 I - AcWing题库 二维(三重循环) 

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int N = 110;
        int[] v = new int[N];
        int[] w = new int[N];
        int[] s = new int[N];
        int[][] f = new int[N][N];
        for(int i = 1; i <= n; i ++){
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
            s[i] = sc.nextInt();
        }
        for(int i = 1; i <= n; i ++){
            for(int j = 0; j <= m ; j ++){
                for(int k = 0; k * v[i] <= j && k <= s[i]; k ++){//与完全背包问题的主要不同
                    f[i][j] = Math.max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);
                }
            }
        }
        System.out.print(f[n][m]);
    }
}

 5. 多重背包问题 II - AcWing题库 (给的数据范围不一样)

二进制优化 

第一种写法 

import java.util.*;
public class Main{
    public static void main(String[] ags){
        Scanner scan = new Scanner(System.in);
        int N = 12000;
        //一个数最多就是2的12次方就会超过题目给的2000,所以1000*12
        int[] v = new int[N];
        int[] w = new int[N];
        int[] f = new int[N];
        int n = scan.nextInt();
        int m = scan.nextInt();
        
        //这个cnt是组合的个数
        int cnt = 0;
        for(int i = 0 ; i < n ; i ++ ){
            int a = scan.nextInt();//体积
            int b = scan.nextInt();//价值
            int s = scan.nextInt();//数量
            
            int k = 1;  //2的0次幂

            //将每一个s都分解成2的多少次幂合
            while(s >= k){
                cnt ++ ;  
                v[cnt] = a * k; 这个组合的体积总数
                w[cnt] = b * k; //这个组合的价值总量
                s -= k;  // s 分解成2的0到k次幂,所以每次s都要减去当前的k
                k *= 2; // k每次都乘以2
            }

            //判断k的很多次幂加起来是不是还差一点才到s
            //假设s为10,那么就是1,2,4,3
            if(s > 0){
                cnt ++;
                v[cnt] = a * s;//这里的s就是上面例子中的3
                w[cnt] = b * s;
            }
        }

        n = cnt; // 将所有组合的值赋值给n

        //用01背包问题的模板来做
        for(int i = 1 ; i <= n ; i ++ )
            for(int j = m ; j >= v[i] ; j --)
                f[j] = Math.max(f[j],f[j - v[i]] + w[i]);

        System.out.println(f[m]);
    }
}

第二种写法

import java.util.*;

//多重背包问题的二进制的第二种写法
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int N = 2010;
        int[] f = new int[N];
        
        int n = sc.nextInt();
        int m = sc.nextInt();
        
        for(int i = 1; i <= n; i ++){
            int v = sc.nextInt();
            int w = sc.nextInt();
            int s = sc.nextInt();
            for(int k = 1; k <= s; k *= 2){
                for(int j = m; j >= k * v; j --){
                    f[j] = Math.max(f[j], f[j - v * k] + w * k);
                }
                s -= k;
            }
            if(s > 0){
                for(int j = m; j >= s * v; j --){
                    f[j] = Math.max(f[j], f[j - v * s] + w * s);
                }
            }
        }
        System.out.print(f[m]);
    }
}

 

6. 多重背包问题 III - AcWing题库

单调队列优化 

 AcWing 6. 多重背包问题 III (包含自己的一些理解,不懂的可以看看) - AcWing

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int N = 1010;
        int M = 20010;
        int[][] f = new int[N][M];
        int[] q = new int[M];//单调队列
        int[] v = new int[M];//体积
        int[] w = new int[M];//价值
        int[] s = new int[M];//数量
        
        int n = sc.nextInt();//物品个数
        int m = sc.nextInt();//背包数量
        for(int i = 1; i <= n; i ++){
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
            s[i] = sc.nextInt();
        }
        
        for(int i = 1; i <= n; i ++){
            for(int r = 0; r < v[i]; r ++){//表示余数
                int hh = 0;//队头
                int tt = -1;//队尾
                for(int j = r; j <= m; j += v[i]){
                    f[i][j] = f[i - 1][j];//一开始不放物品
                    while(hh <= tt && q[hh] < j - v[i] * s[i]) ++ hh;//队头超出滑动窗口
                    //让最大的值移到队头
                    while(hh <= tt && f[i - 1][q[tt]] + (j - q[tt]) / v[i] * w[i] <= f[i - 1][j]) tt --;
                    q[++ tt] = j;
                    f[i][j] = f[i - 1][q[hh]] + (j - q[hh]) / v[i] * w[i];
                }
            }
        }
        System.out.print(f[n][m]);
    }
}

(4)分组背包问题

9. 分组背包问题 - AcWing题库

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int N = 110;
        int[][] v = new int[N][N];
        int[][] w = new int[N][N];
        int[] f = new int[N];
        int[] s = new int[N];
        
        int n = sc.nextInt();
        int m = sc.nextInt();
        for(int i = 1; i <= n; i ++){
            //分成n组,每一组的数量
            s[i] = sc.nextInt();
            //每一组中的物品的体积和价值
            for(int j = 1; j <= s[i]; j ++){
                v[i][j] = sc.nextInt();
                w[i][j] = sc.nextInt();
            }
        }
        
        //和01背包问题很像
        for(int i = 1; i <= n; i ++){
            for(int j = m; j >= 0; j --){
                for(int k = 0; k <= s[i]; k ++){
                    if(v[i][k] <= j) f[j] = Math.max(f[j], f[j - v[i][k]] + w[i][k]);
                }
            }
        }
        System.out.print(f[m]);
    }
}

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值