揹包問題-y總大神(個人筆記,更新中)

揹包九講問題

一.01揹包

題鏈接
問題分析:
dp問題我們一般都是可以採用遞推的方式
對於二維揹包問題,
f[i][j]:表示在看前i個物品的前提下,總體積爲j是最大價值
那麼f[i][j]的值爲:
在考慮前i個物品時並不代表一定要把所有的都算進去
①當第i個物品不算進去時,f[i][j]=f[i-1][j]
②當把第i個物品算進去時,f[i][j]=f[i-1][j-v[i]]+w[i]
result = max(f[N][0-v])
初始化:f[0][0] = 0

import java.util.Scanner;
public class Math {
    public static void main(String[] args) {
       Scanner scan =  new Scanner(System.in);
       int N,V;
       N = scan.nextInt();
       V = scan.nextInt();
       int []w = new int[N+1];
       int []v = new int[N+1];
       int f[][] = new int[N+1][V+1];
       for(int i=1;i<=N;i++)
       {
           v[i] = scan.nextInt();
           w[i] = scan.nextInt();
       }
       //初始化
        f[0][0] = 0;
       for(int i = 1;i<=N;i++)//i從1開始的原因是防止f[i-1][j]越界
           for(int j=0;j<=V;j++)
           {
               f[i][j] = f[i-1][j];
               if(j>= v[i])
               {
                   f[i][j] = java.lang.Math.max(f[i][j],f[i-1][j-v[i]]+w[i]);
               }
           }
        int res = 0;
        for(int i = 1;i<=N;i++)
        {
            res = java.lang.Math.max(res,f[i][V]);
        }
        System.out.println(res);
    }
}

代碼優化:
優化:不用二維,而用一維
f[j]:表示在總體積爲j的情況下的最大價值

import java.util.Scanner;
public class Math {
    public static void main(String[] args) {
       Scanner scan =  new Scanner(System.in);
       int N,V;
       N = scan.nextInt();
       V = scan.nextInt();
       int []w = new int[N+1];
       int []v = new int[N+1];
       int f[] = new int[V+1];
       for(int i=1;i<=N;i++)
       {
           v[i] = scan.nextInt();
           w[i] = scan.nextInt();
       }
       //初始化
        f[0] = 0;
       for(int i=1;i<=N;i++)
           for(int j=V;j>=v[i];j--)//保證f[j-v[i]等於原來的那個f[i-1][j-v[i]],如果j<v[i]那麼直
           //接進入下一個i;而自然的在這個j前面的部分的f[0,1,2....,j-1]還是等於原來的f[j],保持不變
           {
               f[j] = java.lang.Math.max(f[j],f[j-v[i]]+w[i]);
           }
        System.out.println(f[V]);
    }
}

二.完全揹包問題

題鏈接

import java.util.Scanner;

public class Test1 {


    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int N,M;//N代表物品個數,M代表揹包的容量
        N = scan.nextInt();
        M = scan.nextInt();
        int f[] = new int[M+1];//f[i]表示在體積爲i的情況下的最大容量
        int V,W;//是物品的體積,W是物品的價值
        for(int i=1;i<=N;i++)
        {
            V = scan.nextInt();
            W = scan.nextInt();
            for(int j=V;j<=M;j++)//這裏遞增以後便可以重複使用
                f[j] = java.lang.Math.max(f[j],f[j-V]+W);
        }
        System.out.println(f[M]);
        scan.close();
    }
}

三.多重揹包問題

題鏈接

import java.util.Scanner;
public class Main
{
    public static void main(String[] args) {
        int N,V;
        Scanner scanner = new Scanner(System.in);
        N = scanner.nextInt();
        V = scanner.nextInt();
        int v[]=new int[N+1];
        int w[]=new int[N+1];
        int s[]=new int[N+1];
        //初始化條件爲f[0]=0
        int f[] = new int[V+1];
        for(int i=1;i<=N;i++)
        {
            v[i] = scanner.nextInt();
            w[i] = scanner.nextInt();
            s[i] = scanner.nextInt();
        }

        for(int i=1;i<=N;i++)
            for(int j=V;j>=0;j--)
            for(int k=1;j-k*v[i]>=0&&k<=s[i];k++)
            {
                f[j]=java.lang.Math.max(f[j],f[j-k*v[i]]+k*w[i]);
            }
        System.out.println(f[V]);
    }
}

下面是多重揹包的二進制優化方法:

import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;
public class Main
{
    public static void main(String[] args) {
        int N,V;
        List<List<Integer>> lists = new ArrayList<>();
        Scanner scanner = new Scanner(System.in);
        N = scanner.nextInt();
        V = scanner.nextInt();
        int v[]=new int[N+1];
        int w[]=new int[N+1];
        int s[]=new int[N+1];
        //初始化條件爲f[0]=0
        int f[] = new int[V+1];
        for(int i=1;i<=N;i++)
        {
            v[i] = scanner.nextInt();
            w[i] = scanner.nextInt();
            s[i] = scanner.nextInt();
            //二進制分割,下面的代碼可以取s[i]=10驗證分割爲1,2,4,3
            for(int k=1;k<=s[i];k=2*k)
            {
                s[i]-=k;
                List<Integer> list = new ArrayList<>();
                list.add(k*v[i]);
                list.add(k*w[i]);
                lists.add(list);
            }
            if(s[i]>0)
            {
                List<Integer> list = new ArrayList<>();
                list.add(s[i]*v[i]);
                list.add(s[i]*w[i]);
                lists.add(list);
            }
        }
        //套用01揹包
        for(List<Integer> list : lists)
        {
            for(int j=V;j>=0;j--)
            {
                if(j-list.get(0)>=0)
                f[j]=java.lang.Math.max(f[j],f[j-list.get(0)]+list.get(1));
            }
        }
        System.out.println(f[V]);
    }
}

下面是單調隊列優化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章