本文主要是介绍北大oj Coins,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Problem: 北大oj Coins
文章目录
- 思路
- 解题方法
- 复杂度
- Code
思路
题目要求我们找出所有可能组成的金额总数,给定一系列硬币面值和每种硬币的数量。我们使用动态规划来解决这个问题。关键在于如何处理每种硬币数量大于1的情况,这需要对余数进行分组,以便于在遍历时能够有效地更新状态。
解题方法
我们首先初始化一个布尔数组dp,其长度为最大目标金额m加上1。数组中的每个元素表示是否可以组成对应位置的金额。接下来,对于每种硬币,根据其数量的不同,采取不同的策略更新dp数组。如果硬币数量为1,则直接更新dp数组;如果硬币数量多且硬币总价值大于m,则可以视为无限数量的硬币;否则,需要根据余数进行分组更新。
复杂度
时间复杂度:
O ( n × m ) O(n×m) O(n×m),其中n是硬币种类数,m是目标金额。
空间复杂度:
O ( m ) O(m) O(m),主要取决于dp数组的大小。
Code
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;public class Main {static int MAXN = 110;static int MAXM = (int) (1e5 + 10);static int[] val = new int[MAXN];static int[] cnt = new int[MAXN];static boolean[] dp = new boolean[MAXM];static int n, m;public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));StreamTokenizer in = new StreamTokenizer(br);PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));while (in.nextToken() != StreamTokenizer.TT_EOF) {n = (int) in.nval;in.nextToken();m = (int) in.nval;if (n != 0 || m != 0) {for (int i = 1; i <= n; i++) {in.nextToken();val[i] = (int) in.nval;}for (int i = 1; i <= n; i++) {in.nextToken();cnt[i] = (int) in.nval;}out.println(deal());}}out.flush();out.close();br.close();}private static int deal() {// TODO Auto-generated method stubArrays.fill(dp, 1, m + 1, false);dp[0] = true;for(int i = 1; i <= n; i++) {if(cnt[i] == 1) {for(int j = m ; j >= val[i]; j--) {if(dp[j - val[i]]) {dp[j] = true;}}} else if(val[i] * cnt[i] > m) {for(int j = val[i]; j <= m; j++) {if(dp[j - val[i]]) {dp[j] = true;}}} else {// 根据余数分组for (int mod = 0; mod < val[i]; mod++) {int trueCnt = 0;for (int j = m - mod, size = 0; j >= 0 && size <= cnt[i]; j -= val[i], size++) {trueCnt += dp[j] ? 1 : 0;}for (int j = m - mod, l = j - val[i] * (cnt[i] + 1); j >= 1; j -= val[i], l -= val[i]) {if (dp[j]) {trueCnt--;} else {if (trueCnt != 0) {dp[j] = true;}}if (l >= 0) {trueCnt += dp[l] ? 1 : 0;}}}}}int ans = 0;for(int i = 1; i <= m; i++) {if(dp[i]) {ans++;}}return ans;}}
这篇关于北大oj Coins的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!