输入包括两行,第一行两个整数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;
}