day15 1371 Currency system (complete knapsack problem)

1371. Currency System

Given VVV currencies (unit: yuan), the number of times each currency can be used is unlimited.

Different currencies may have the same face value.

Now, I want you to use this VVV currencies make upNNN yuan, how many different methods are there?

Input format The
first line contains two integers VVV andNNN

In the next few lines, a total of VV will be enteredV integers, each integer represents the denomination of a currency.

Output format
Output an integer, representing the total number of solutions requested.

Data range
1 ≤ V ≤ 25 1≤V ≤251V25,
1 ≤ N ≤ 10000 1≤N≤10000 1N1 0 0 0 0 The
answer is guaranteed to be inlong longlong l o n g long Within the range of l o n g .

Input sample:

3 10
1 2 5

Sample output:

10

Idea: DP analysis

Insert picture description here
Status indication: It f[i][j] indicates the number of schemes in the set of all selection methods that are iselected from the previous currency and jwhose total value does not exceed .

Then f[n][m]it means that the number of options in the set of all options that nare selected from the previous currency and mwhose total value does not exceed is the answer.

Set division:

In accordance with section icurrencies can choose 0a, 1a, 2a, 3a ,,,,knumber of segmented collection f[i][j]. Among them k*w[i] <= j, that is to say, in the case that the backpack can be loaded, the enumerated first icurrency can choose several.

State calculation:

f[i][j] = f[i-1][j]+f[i-1][j-w[i]]+f[i-1][j-2*w[i]],,,,,,+f[i-1][j-k*w[i]]

Java code


import java.util.Scanner;

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        //用n种货币凑成m元钱的方案数,方案数可能很大,故用long型
        long[][] dp = new long[n + 1][m + 1];
        //初始化,用0种货币凑成0元钱的方案数是1,其余dp[0][j]默认是0
        //即用0种货币凑成j(j!=0)元钱的方案数是0
        dp[0][0] = 1;

        for(int i = 1;i <= n;i++){
    
    
            int v = scanner.nextInt();//当前货币
            for(int j = 0;j <= m;j++){
    
    
                for(int k = 0; k*v <= j; k++){
    
    //当前货币使用0~k次
                    dp[i][j] += dp[i-1][j-k*v];
                }
            }
        }
        System.out.println(dp[n][m]);
    }
}

Consider optimization

vRepresents ithe volume of the first article (face value)

Select from the previous icurrency, jthe state of not exceeding the value is expressed as:
f[i][j] = f[i-1][j] + f[i-1][j-v]+f[i-1][j-2v]+,,,,,+f[i-1][j-kv])
Select from the previous icurrency, j-vthe state of not exceeding the value, expressed as:
f[i][j-v] = f[i-1][j-v]+f[i-1][j-2v]+,,,,,+f[i-1][j-kv])

Subtract the two types to get:

f[i][j] = f[i-1][j]+f[i][j-v])

Java code


import java.util.Scanner;

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        //用n种货币凑成m元钱的方案数,方案数可能很大,故用long型
        long[][] dp = new long[n + 1][m + 1];
        //初始化,用0种货币凑成0元钱的方案数是1,其余dp[0][j]默认是0
        //即用0种货币凑成j(j!=0)元钱的方案数是0
        dp[0][0] = 1;

        for(int i = 1;i <= n;i++){
    
    
            int v = scanner.nextInt();//当前货币
            for(int j = 0;j <= m;j++){
    
    
               dp[i][j] = dp[i-1][j];
               if(j >= v) dp[i][j] += dp[i][j-v];
            }
        }
        System.out.println(dp[n][m]);
    }
}

Consider continuing to optimize and become a one-dimensional DP that
has been obtained from the above f[i][j] = f[i-1][j]+f[i][j-v]). We found f[i][j]that the outer forloop is ithe value of the first loop, and only the value of the outer forloop is i-1the value of the first loop, so we can do An equivalent transformation turns the above formula into:
f[j] = f[j] + f[j-v]

So f[j] = f[j] + f[j-v]why is it f[i][j] = f[i-1][j]+f[i][j-v])equal to?

  1. The right side of the equal sign f[j]is used to update the current one on the left f[j]. Note that the current outer forloop is the first iloop, while the right side of the equal sign is calculated during the f[j]previous forloop, that is, the outer forloop is i - 1calculated and saved at time f[j], That is f[i-1][j].
  2. The one on the right side of f[j-v]the equal sign is because forwe update from small to large in the inner loop, and j-vmust be less than jthat, so before seeking f[j], f[j-v]it has been calculated and updated to the value when the outer forloop was the first iloop, that is f[i][j-v]. So f[j] = f[j] + f[j-v]why is the above f[i][j] = f[i-1][j]+f[i][j-v])equivalent.

Java code


import java.util.Scanner;

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        //用n种货币凑成m元钱的方案数,方案数可能很大,故用long型
        long[] dp = new long[m + 1];
        //初始化,用0种货币凑成0元钱的方案数是1,其余dp[0][j]默认是0
        //即用0种货币凑成j(j!=0)元钱的方案数是0
        dp[0] = 1;

        /*for(int i = 1;i <= n;i++){
            int v = scanner.nextInt();//当前货币
            for(int j = 0;j <= m;j++){
            //内层for循环中就一个if语句,我们发现if语句中的条件还可以提到for中,故还可简化为下面的写法
               if(j >= v) dp[j] += dp[j-v]; 
            }*/
        for(int i = 1;i <= n;i++){
    
    
            int v = scanner.nextInt();//当前货币
            for(int j = v;j <= m;j++){
    
    
               dp[j] += dp[j-v];
            }
        }
        System.out.println(dp[m]);
    }
}

Insert picture description here

Guess you like

Origin blog.csdn.net/YouMing_Li/article/details/113869701