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 ≤251≤V≤25,
1 ≤ N ≤ 10000 1≤N≤10000 1≤N≤1 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
Status indication: It f[i][j]
indicates the number of schemes in the set of all selection methods that are i
selected from the previous currency and j
whose total value does not exceed .
Then f[n][m]
it means that the number of options in the set of all options that n
are selected from the previous currency and m
whose total value does not exceed is the answer.
Set division:
In accordance with section i
currencies can choose 0
a, 1
a, 2
a, 3
a ,,,,k
number 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 i
currency 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
v
Represents i
the volume of the first article (face value)
Select from the previous i
currency, j
the 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 i
currency, j-v
the 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 for
loop is i
the value of the first loop, and only the value of the outer for
loop is i-1
the 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?
- The right side of the equal sign
f[j]
is used to update the current one on the leftf[j]
. Note that the current outerfor
loop is the firsti
loop, while the right side of the equal sign is calculated during thef[j]
previousfor
loop, that is, the outerfor
loop isi - 1
calculated and saved at timef[j]
, That isf[i-1][j]
. - The one on the right side of
f[j-v]
the equal sign is becausefor
we update from small to large in the inner loop, andj-v
must be less thanj
that, so before seekingf[j]
,f[j-v]
it has been calculated and updated to the value when the outerfor
loop was the firsti
loop, that isf[i][j-v]
. Sof[j] = f[j] + f[j-v]
why is the abovef[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]);
}
}