输入包括两行,第一行两个整数n(0<=n<=1000)代表数组长度和aim(0<=aim<=5000),第二行n个不重复的正整数,代表arr。
输出一个整数,表示组成aim的最小货币数,无解时输出-1.
3 20 5 2 3
4
20=5*4
3 0 5 2 3
0
2 2 3 5
-1
时间复杂度,空间复杂度。
#include<iostream> #include<vector> #include<algorithm> using namespace std; //第一想法:暴力搜索,过程是先从大到小sort钱币数组,去数组第一个最大值可取得的最多张钱,然后贪心的后找剩余钱,若找不到; //逐步回溯到上次,减少取钱的数目,若回溯到了最开始的地方,且都没找到,取第二大的值,进行同样操作; //递归设计,设minMoney为给定了钱币数组arr,从cur开始取钱,取total数目的钱的最少货币数。 int minMoney1(const vector<int> &arr, int cur, int total) { for(int i=cur; i<arr.size(); ++i) { int num = total / arr[i]; //当前取多少钱 int resi = total % arr[i]; //还剩多少要取; if(num==0) return minMoney1(arr, cur+1, total); if(resi==0) return num; //已经取完了; else return num + minMoney1(arr, cur+1, resi); } return -1; } //不用先sort钱币数组arr的暴力搜索: int process(const vector<int> &arr, int i, int rest) { if(i == arr.size()) return (rest==0) ? 1: 0; //最少张数,初始为-1,因为还没有找到有效解 int res = -1; //一次使用卡片k张; for(int k=0; k*arr[i]<=rest; k++) { int next = process(arr, i+1, rest - k*arr[i]); if(next != -1)//说明这个过程有效 res = res == -1 ? next+k: min(res, next+k); } return res; } //dp:无后效性:前面用了x张面值为t1的钱币,用了y张面值为t2的钱币;x*t1==y*t2,此时后续的搜索是同样的结果,因此无后效性; //cur的范围:从0<=cur<=N,即迭代所有的面值;total的范围:从0<=total<=total; //每行是迭代的面值,每列是迭代的剩余值,面值从0取到N结束,再判断是都是有效的,也就是最后的剩余值为0,即DP[N][0]处; //最终状态:有效位置dp[N][0]处为0,其余部分是-1;dp[0][total]为题目要求的结果; int minMoney2(const vector<int> &arr, int total) { int N = arr.size(); vector< vector<int>> dp(N+1,vector<int>(total+1, 0)); //设置最后一排的值 for(int i=1; i<=total; ++i) dp[N][i] = -1; for(int i=N-1; i>=0; --i) //最后一排是已知状态,没次向上计算; { for(int rest=0; rest<=total; ++rest) { dp[i][rest] = -1; //先置位默认-1; if(dp[i+1][rest] != -1){ // 有效位置 dp[i][rest] = dp[i+1][rest]; } //如果左边的位置不越界且有效 if(rest-arr[i]>=0 && dp[i][rest-arr[i]] != -1){ if(dp[i][rest] == -1){ //之前下面的值为无效的值 dp[i][rest] = dp[i][rest-arr[i]] + 1; }else{ dp[i][rest] = min(dp[i][rest], dp[i][rest-arr[i]] + 1); } } } } return dp[0][total]; } //单行迭代更新:只需要拿走上面代码中的[i]循环,并且记录上一次里rest的值:dp[i][rest] = dp[i+1][rest]; int minMoney3(const vector<int> &arr, int total) { int N = arr.size(); vector<int> dp(total+1, 0); for(int i=1; i<=total; ++i) dp[i] = -1; for(int i=N-1; i>=0; --i) //每次更新一行 { for(int rest=0; rest<=total; ++rest) //一行一共total列 { int tmp = dp[rest]; //上一轮的rest处的结果 dp[rest] = -1; //先置位默认-1; if(tmp != -1){ dp[rest] = tmp; } if(rest-arr[i]>=0 && dp[rest-arr[i]]!= -1){ if(dp[rest] == -1) dp[rest] = dp[rest-arr[i]] + 1; else dp[rest] = min(dp[rest], dp[rest-arr[i]] +1); } } } return dp[total]; } int main() { int length, aim; cin >> length >> aim; if(length==0 || aim<0) return 0; vector<int> arr(length, 0); for(int i=0; i<length; ++i) cin >> arr[i]; cout << minMoney3(arr, aim) << endl; }
#include <iostream> #include <queue> #include <string> #include <climits> #include <stack> #include <list> #include <algorithm> #include <map> #include <cmath> using namespace std; int main() { //freopen("in", "r", stdin); int n,V; cin>>n>>V; vector<long long> dp(V+1, INT_MAX); dp[0] = 0; for(int i = 1;i<=n;i++) { long long cost; cin>>cost; for(int v = cost; v<=V;v++){ dp[v] = min(dp[v - cost] + 1, dp[v]); } } if(dp[V]==INT_MAX) cout<< -1 <<endl; else cout<<dp[V]<<endl; return 0; }
#include <stdio.h> #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) int main(void) { int n, aim; scanf("%d %d", &n, &aim); if (n == 0) printf("%d\n", -1); int arr[n]; for (int i = 0; i < n; i++) { scanf("%d", arr + i); } int tmp; int dp[aim + 1]; dp[0] = 0; for (int i = n - 1; i >= 0; i--) { for (int rest = 1; rest <= aim; rest++) { tmp = -1; if (rest - arr[i] >= 0 && dp[rest - arr[i]] != -1) { tmp = 1 + dp[rest - arr[i]]; } if (i != n-1 && dp[rest] != -1) { tmp = tmp == -1 ? dp[rest] : MIN(tmp, dp[rest]); } dp[rest] = tmp; } } printf("%d\n", dp[aim]); return 0; }
const [n, aim] = readline().split(' ').map(Number); const arr = readline().split(' ').map(Number); function initDimensionTwoArray(rNum, cNum) { const res = []; for (let i = 0; i < rNum; i++) { const row = []; for (let j = 0; j < cNum; j++) { row.push(Number.MAX_SAFE_INTEGER); } res.push(row); } return res; } // 初始化一个二维dp表,并初始化每个单元格的值为0 const dp = new Array(aim + 1).fill(0); // 初始化dp表第一行,只用arr[0]的面值找出0...aim的货币所用的最少张数 // 显然,arr[0]只能找它的倍数的货币 for (let j = 1; j < aim + 1; j++) { dp[j] = Number.MAX_SAFE_INTEGER; if (j >= arr[0] && dp[j - arr[0]] !== dp[j]) { dp[j] = dp[j - arr[0]] + 1; } } for (let i = 1; i < n; i++) { for (let j = 1; j < aim + 1; j++) { let max = Number.MAX_SAFE_INTEGER; if (j >= arr[i] && dp[j - arr[i]] !== max) { max = dp[j - arr[i]] + 1; } dp[j] = Math.min(max, dp[j]); } } console.log(dp[aim] !== Number.MAX_SAFE_INTEGER ? dp[aim] : -1);
import java.io.*; import java.util.Arrays; public class Main{ public static void main(String[] args) throws IOException{ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String[] str = reader.readLine().split(" "); int[] arr = parse(str,2); int n = arr[0]; int amount = arr[1]; arr = parse(reader.readLine().split(" "),n); reader.close(); System.out.println(coinChange(arr,amount)); } private static int coinChange(int[] coins, int amount) { int max = amount + 1; int[] dp = new int[amount + 1]; Arrays.fill(dp, max); dp[0] = 0; for (int i = 1; i <= amount; i++) { for (int j = 0; j < coins.length; j++) { if (coins[j] <= i) { dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); } } } return dp[amount] > amount ? -1 : dp[amount]; } private static int[] parse(String[] str,int len){ int[] arr = new int[len]; for(int i= 0;i < len;++i){ arr[i] = Integer.parseInt(str[i]); } return arr; } }
import java.util.*; public class P189 { public static int process(int[] arr, int N, int aim) { int[] dp = new int[aim + 1]; Arrays.fill(dp, -1); dp[0] = 0; for (int i = N - 1; i >= 0; i--) { for (int rest = 0; rest <= aim; rest++) { if (rest - arr[i] >= 0 && dp[rest - arr[i]] != -1) { if (dp[rest] != -1) { dp[rest] = Math.min(dp[rest], dp[rest - arr[i]] + 1); } else { dp[rest] = dp[rest - arr[i]] + 1; } } } } return dp[aim]; } public static void main(String[] args) { Scanner sc = new Scanner(System.in); int N = sc.nextInt(); int aim = sc.nextInt(); int[] arr = new int[N]; for (int i = 0; i < N; i++) { arr[i] = sc.nextInt(); } System.out.println(process(arr, N, aim)); } }
#include<iostream> #include<vector> #include<algorithm> using namespace std; int main() { int length, aim; cin >> length >> aim; if(length==0 || aim<0) return 0; vector<int> arr(length, -1); for(int i=0; i<length; ++i) cin >> arr[i]; vector<int> dp(aim+1, -1); dp[0] = 0; for(int i = 1; i < aim+1; i++){ if(i % arr[0] == 0) dp[i] = i / arr[0]; } for(int i = 1; i < length; i++){ for(int j = 1; j < aim+1; j++){ if(j < arr[i]) continue; else if(dp[j-arr[i]] != -1 && dp[j] != -1){ dp[j] = min(dp[j], dp[j-arr[i]]+1); } else if(dp[j-arr[i]] != -1){ dp[j] = dp[j-arr[i]]+1; } else continue; } } cout << dp[aim]; }动态规划,12ms
#include <iostream> (720)#include <vector> using namespace std; int chargecoin(vector<int>& n,int aim){ int MAX = 99999; int len = n.size(); if (aim <= 0 || len == 0){ return -1; } vector<vector<int> > dp(len,vector<int>(aim + 1,0)); //首行初始化 for (int i = 1;i <= aim;i++){ dp[0][i] = MAX; if (i >= n[0] && dp[0][i - n[0]] != MAX){ dp[0][i] = dp[0][i - n[0]] + 1; } } //逐行进行动态规划 for (int i = 1;i < len;i++){ for (int j = 1;j <= aim;j++){ int rest = MAX; if (j >= n[i] && dp[i][j - n[i]] != MAX){ rest = dp[i][j - n[i]] + 1; } dp[i][j] = min(dp[i - 1][j],rest); } } //返回最少货币数,无解的情况下返回 -1 return dp[len - 1][aim] == MAX ? -1 : dp[len - 1][aim]; } int main(){ int n,aim; int result = 0; cin >> n >> aim; vector<int> nums(n); for (int i = 0;i < n;i++){ cin >> nums[i]; } cout << chargecoin(nums,aim) << endl; return 0; }
#include<cstdio> #include<iostream> using namespace std; int main(){ int n,aim; cin>>n>>aim; int a[n]; int dp[aim+1]; for(int i=0;i<n;i++){ cin>>a[i]; } dp[0] = 0; for(int i=1;i<=aim;i++){ if(i>=a[0]&&(i%a[0]==0)){ dp[i] = (i/a[0]); }else{ dp[i] = -1; } } for(int i=1;i<n;i++){ for(int j=1;j<=aim;j++){ if(j>=a[i]){ if(dp[j-a[i]]==-1) dp[j] = dp[j]; else if(dp[j]==-1) dp[j] = dp[j-a[i]]+1; else dp[j] = min(dp[j],dp[j-a[i]]+1); } } } cout<<dp[aim]<<endl; return 0; }
#include <bits/stdc++.h> using namespace std; int main(){ int n, m, x; cin>>n>>m; int dp[m+1]; fill(dp,dp+m+1,INT_MAX); dp[0] = 0; for(int i=0;i<n;i++){ cin>>x; for(int j=x;j<=m;j++) dp[j] = min(dp[j], dp[j-x]+1); } cout<<(dp[m]==INT_MAX?-1:dp[m])<<endl; return 0; }
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.util.Arrays; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] params = br.readLine().trim().split(" "); int n = Integer.parseInt(params[0]), target = Integer.parseInt(params[1]); String[] strArr = br.readLine().trim().split(" "); int[] coins = new int[n]; for(int i = 0; i < n; i++) coins[i] = Integer.parseInt(strArr[i]); int[] dp = new int[target + 1]; Arrays.fill(dp, 1, dp.length, Integer.MAX_VALUE); for(int coin: coins){ for(int j = coin; j <= target; j++) if(dp[j - coin] != Integer.MAX_VALUE) dp[j] = Math.min(dp[j], dp[j - coin] + 1); } System.out.println(dp[target] == Integer.MAX_VALUE? -1: dp[target]); } }
N, K = list(map(int, input().split())) nums = list(map(int, input().split())) dp = [float('inf')]*(K+1) dp[0] = 0 for i in range(1, K+1): for j in range(N): if i < nums[j]: continue dp[i] = min(dp[i], dp[i-nums[j]]+1) if dp[K] == float('inf'): print(-1) else: print(dp[K])
#include "bits/stdc++.h" using namespace std; int main() { int len;cin>>len; int target;cin>>target; vector<int> nums(len); for(int i=0;i<len;i++)cin>>nums[i]; sort(nums.begin(),nums.end(),greater<int>()); vector<int> ret(target+1,INT_MAX); ret[0]=0; for(int i=0;i<=target;i++) { for(int j=0;j<len;j++) { if(i-nums[j]>=0&&ret[i-nums[j]]!=INT_MAX) { ret[i]=min(ret[i],ret[i-nums[j]]+1); } } } if(ret[target]==INT_MAX) cout<<-1; else cout<<ret[target]; return 0; }
n,m=input().split() l=list(map(int,input().split())) n=int(n) m=int(m) l.sort() def fun(n,m,l): if m==0: return 0 if m<l[0]: return -1 dp=[0 for i in range(m+1)] #dp[0]=0 for i in range(n): a=l[i] if a>m: break dp[a]=1 for j in range(a+1,m+1): if dp[j-a]>0: if dp[j]==0: dp[j]=dp[j-a]+1 else: dp[j]=min(dp[j],dp[j-a]+1) if dp[m]>0: return dp[m] else: return -1 print(fun(n, m, l))
#include <iostream> #include <limits.h> #include <vector> #include <algorithm> using namespace std; int process(int i, int rest, const vector<int>& v){ if(rest < 0) return -1; if(rest == 0) return 0; //rest > 0 if(i == v.size()) return -1; //rest > 0 i < v.size() int minVal = INT_MAX; for(int num = 0; num * v[i] <= rest; num++){ int tmp = process(i + 1, rest - num * v[i], v); if(tmp != -1) minVal = min(tmp + num, minVal); } return minVal == INT_MAX ? -1 : minVal; } int way1(int aim, const vector<int>& v){ return process(0, aim, v); } int main(void){ int n, aim; cin >> n >> aim; vector<int> v(n); for(int i = 0; i < n; i++){ cin >> v[i]; } cout << way1(aim, v) << endl; return 0; }
#include <iostream> #include <limits.h> #include <vector> #include <algorithm> using namespace std; int way3(int aim, const vector<int>& v){ vector<vector<int>> dp(v.size() + 1, vector<int>(aim + 1, -1)); for(int i = 0; i <= v.size(); i++) dp[i][0] = 0; for(int rest = 1; rest <= aim; rest++) dp[v.size()][rest] = -1; for(int i = v.size() - 1; i >= 0; i--){ for(int rest = 1; rest <= aim; rest++){ int minVal = INT_MAX; for(int num = 0; num * v[i] <= rest; num++){ int tmp = dp[i + 1][rest - num * v[i]]; if(tmp != -1) minVal = min(tmp + num, minVal); } dp[i][rest] = minVal == INT_MAX ? -1 : minVal; } } return dp[0][aim]; } int main(void){ int n, aim; cin >> n >> aim; vector<int> v(n); for(int i = 0; i < n; i++){ cin >> v[i]; } cout << way3(aim, v) << endl; return 0; }不做斜率优化的递归解法
#include <iostream> #include <limits.h> #include <vector> #include <algorithm> using namespace std; int way3(int aim, const vector<int>& v){ vector<vector<int>> dp(v.size() + 1, vector<int>(aim + 1, -1)); for(int i = 0; i <= v.size(); i++) dp[i][0] = 0; for(int rest = 1; rest <= aim; rest++) dp[v.size()][rest] = -1; for(int i = v.size() - 1; i >= 0; i--){ for(int rest = 1; rest <= aim; rest++){ int minVal = INT_MAX; if(dp[i + 1][rest] != -1) minVal = min(minVal, dp[i + 1][rest]); if(rest - v[i] >= 0 && dp[i][rest - v[i]] != -1) minVal = min(minVal, dp[i][rest - v[i]] + 1); dp[i][rest] = minVal == INT_MAX ? -1 : minVal; } } return dp[0][aim]; } int main(void){ int n, aim; cin >> n >> aim; vector<int> v(n); for(int i = 0; i < n; i++){ cin >> v[i]; } cout << way3(aim, v) << endl; return 0; }斜率优化后的递归算法,
转化为完全背包求解
/* * @Description: 换钱的最少货币数 * @Author: * @Date: 2020-10-26 15:30:58 * @LastEditTime: 2020-10-26 20:03:26 * @LastEditors: Please set LastEditors */ #include<iostream> #include<vector> #include<algorithm> #include<climits> using namespace std; int MAX = 99999; int main(){ int n,aim; cin >> n >> aim; if(aim <= 0 || n == 0){ return -1; } vector<int> dp(aim + 1,MAX); dp[0] = 0; int money; for(int i = 1;i <= n;i++){ cin >> money; for(int j = money;j <= aim;j++){ dp[j] = min(dp[j], dp[j - money] + 1); } } cout << (dp[aim] == MAX ? -1 : dp[aim]) << endl; //system("pause"); return 0; }
#include <bits/stdc++.h> using namespace std; int main(){ int n, aim; cin>>n>>aim; if(aim==0){ cout<<0; return 0; } if(n == 0){ cout<<-1; return 0; } vector<int> v(aim+1, -1); // 多一个0元素,避免漏掉5找5这种整倍情况 v[0] = 0; int coin; while(n > 0){ // 大循环,每次读入一个币值 --n; cin>>coin; for(int i=1;i<=aim;++i){ int diff = i - coin; if(diff>=0 && v[diff]!=-1) // 如果aim-coin不越界且是能实现的兑换 v[i] = (v[i]>0? min(v[i], 1+v[diff]):1+v[diff]); // 在有效值中找较小的更新当前值 } } cout<<v[aim]; return 0; }