输出包括两行,第一行包括两个整数n和aim
。第二行包含n个整数,表示arr数组
。
输出一个整数,表示换钱的方法数对取模后的答案。
4 15 5 10 25 1
6
5*3=15
10*1+5*1=15
10*1+1*5=15
1*10+5*1=15
5*2+1*5=15
1*15=15
5 1000 2 3 5 7 10
20932712
时间复杂度,空间复杂度
。
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9+7;
int main(){
int n, m;
cin>>n>>m;
long a[n], dp[m+1];
memset(dp, 0, sizeof(dp));
for(int i=0;i<n;i++)
cin>>a[i];
dp[0] = 1;
for(int i=0;i<n;i++)
for(int j=a[i];j<=m;j++)
dp[j] = (dp[j]+dp[j-a[i]])%MOD;
cout<<dp[m]%MOD<<endl;
return 0;
} #include<bits/stdc++.h>
using namespace std;
int main()
{
int n,aim,M=1e9+7;
cin>>n>>aim;
if(n==0||aim<0)
{
cout<<-1<<endl;
return 0;
}
vector<int>arr(n);
for(int i=0;i<n;i++)
cin>>arr[i];
vector<int>dp(aim+1,0);
dp[0]=1; // 组成0元的个数
for(int i=0;i<n;++i)
for(int j=arr[i];j<=aim;++j)
dp[j]=(dp[j]+dp[j-arr[i]])%M;
cout<<dp[aim]<<endl;
return 0;
} import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
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]);
int target = Integer.parseInt(params[1]);
final int MOD = 1000000007;
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];
dp[0] = 1;
for(int coin: coins){
for(int i = coin; i <= target; i++)
dp[i] = (dp[i] + dp[i - coin]) % MOD;
}
System.out.println(dp[target]);
}
} 如果动态规划的状态转移方程一开始很难想到,那我们可以通过记忆化搜索的递归版解法改编过来,只是将递归的调用,改成从DP表中取值就行: import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
static final int MOD = 1000000007;
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]);
int 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[][] memory = new int[n + 1][target + 1];
// 从左边的硬币开始使用,往右尝试
System.out.println(recurrent(coins, 0, target, memory));
}
private static int recurrent(int[] coins, int index, int rest, int[][] memory) {
if(index == coins.length){
return rest == 0? 1: 0;
}else{
// 缓存命中直接返回
if(memory[index][rest] > 0) return memory[index][rest];
// 否则递归计算
memory[index][rest] = (recurrent(coins, index + 1, rest, memory) + (rest - coins[index] >= 0? recurrent(coins, index, rest - coins[index], memory): 0)) % MOD;
return memory[index][rest];
}
}
} import scala.io.StdIn
object Main {
def main(args: Array[String]): Unit = {
val in = StdIn
var params = in.readLine().split(" ")
val n = params(0).toInt
val aim = params(1).toInt
params = in.readLine().split(" ")
val coins = Array.ofDim[Int](n)
for(i <- coins.indices) coins(i) = params(i).toInt
val dp = Array.ofDim[Long](n + 1, aim + 1)
dp(n)(0) = 1
for(index <- n - 1 to 0 by -1; rest <- 0 to aim){
dp(index)(rest) = dp(index + 1)(rest)
if(rest - coins(index) >= 0) dp(index)(rest) = (dp(index)(rest) + dp(index)(rest - coins(index))) % 1000000007
}
println(dp(0)(aim))
}
} #include "bits/stdc++.h"
using namespace std;
int main()
{
const int M=1e9+7;
int N;cin>>N;
int aim;cin>>aim;
vector<int> money(N);
for(int i=0;i<N;i++)cin>>money[i];
//sort(money.begin(),money.end());
vector<int> dp(aim+1,0);
//cout<<1;
dp[0]=1;
for(int j=0;j<N;j++)
{
for(int i=money[j];i<=aim;i++)
{
//if(i>money[j]){
dp[i]=(dp[i]+dp[i-money[j]])%M;
//else if(i==money[j])dp[i]++;
}
//cout<<dp[i]<<' ';
}
cout<<dp[aim];
return 0;
} import java.util.*;
public class Main {
public static int mod = (int) 1e9+7;
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(numDP(arr, aim));
}
public static int numDP (int[] arr, int aim) {
if (arr == null || arr.length < 1 || aim < 0)
return 0;
int n = arr.length;
long[][] dp = new long[n+1][aim+1];
dp[n][0] = 1;
for (int i = n-1; i >= 0; i--) {
for (int j = 0; j<=aim; j++) {
dp[i][j] = (dp[i+1][j]) % mod;
if (j - arr[i] >= 0)
dp[i][j]+= (dp[i][j-arr[i]]) % mod;
dp[i][j] = dp[i][j] % mod;
}
}
return (int)dp[0][aim];
}
} #include <iostream>
#include <vector>
using namespace std;
const int mod = 1e9 + 7;
int process(int i, int rest, const vector<int>& v, vector<vector<int>>& dp){
if(rest < 0)
return 0;
if(dp[i][rest] != -1)
return dp[i][rest];
if(rest == 0){
dp[i][rest] = 1;
return dp[i][rest];
}
//rest > 0
if(i == v.size()){
dp[i][rest] = 0;
return dp[i][rest];
}
//rest > 0 ; i < v.size()
long ans = 0;
for(int num = 0; num * v[i] <= rest; num++){
ans += (process(i + 1, rest - num * v[i], v, dp) % mod);
}
dp[i][rest] = ans % mod;
return dp[i][rest];
}
int way(int aim, const vector<int>& v){
vector<vector<int>> dp(v.size() + 1, vector<int>(aim + 1, -1));
return process(0, aim, v, dp);
}
int main(void){
int n, aim;
cin >> n >> aim;
vector<int> v(n);
for(int i = 0; i < n; i++){
cin >> v[i];
}
cout << way(aim, v) << endl;
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
const int mod = 1e9 + 7;
int way3(int aim, const vector<int>& v){
int N = v.size();
vector<vector<int>> dp(N + 1, vector<int>(aim + 1));
for(int i = 0; i <= N; i++)
dp[i][0] = 1;
for(int i = N - 1; i >= 0; i--){
for(int rest = 1; rest <= aim; rest++){
dp[i][rest] = dp[i + 1][rest];
if(rest - v[i] >= 0)
dp[i][rest] = ((long)dp[i][rest] + (long)dp[i][rest - v[i]]) % mod;
}
}
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 <cstdio>
#define mod 1000000007;
long long n, aim, arr[1010], dp[20010] = {1}, i, j;
int main(){
scanf("%lld %lld", &n, &aim);
for(i = 0; i < n; i++) scanf("%lld", &arr[i]);
for(j = n-1; j >= 0; j--)
for(i = arr[j]; i <= aim; i++)
dp[i] = (dp[i] + dp[i - arr[j]]) % mod;
printf("%lld", dp[aim]);
}
import java.util.*;
public class Main {
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+1];
for(int i=1;i<=n;i++){
arr[i]=sc.nextInt();
}
long[] dp = new long[aim+1];
dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=arr[i];j<=aim;j++){
dp[j] = (dp[j]+dp[j-arr[i]])%1000000007;
}
}
System.out.println(dp[aim]);
}
}
完全背包求方案数
dp[j]:考虑前 n 种货币,组成面值 j 的方案数
import java.util.Scanner;
public class Main {
static int N = 20010;
static int mod = (int) (1e9 + 7);
static int n, aim;
static int[] dp = new int[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
aim = sc.nextInt();
dp[0] = 1;
for (int i = 0; i < n; i++) {
int v = sc.nextInt();
for (int j = v; j <= aim; j++) {
dp[j] = (dp[j] + dp[j - v]) % mod;
}
}
System.out.println(dp[aim]);
}
}
import java.util.*;
public class Main {
public static final int mod = 1_000_000_007;
public static int process(int[] arr, int n, int aim) {
if (arr == null || arr.length == 0) return 0;
int[] dp = new int[aim + 1];
for (int i = 0; i < n; i++) {
dp[0] = 1;
for (int target = 0; target <= aim; target++) {
if (target - arr[i] >= 0) {
if (i == 0)
dp[target] = dp[target - arr[i]];
else
dp[target] = (dp[target] + dp[target - arr[i]]) % mod;
}
}
}
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>
(720)#include<vector>
using namespace std;
int change(int amount, vector<int> &coins) {
int mod = 1e9 + 7;
if (amount == 0) return 1;
if (coins.size() == 0) return 0;
vector<int> dp(amount + 1, 0);
dp[0] = 1;
for (int i = 0; i < coins.size(); i++) {
for (int j = coins[i]; j <= amount; j++) {
dp[j] += dp[j - coins[i]];
dp[j] %= mod;
}
}
return dp[amount];
}
int main () {
int n, aim;
cin >> n >> aim;
int *arr = new int[n];
vector<int> tmp;
for (int i = 0; i < n; i++) {
cin >> arr[i];
tmp.push_back(arr[i]);
}
cout << change(aim, tmp) << endl;
return 0;
} clear code to easy understand//完全背包问题变种,二维数组会内存超限,所以用滚动数组实现1维的dp
#include<cstdio>
#include<iostream>
#include<cstdlib>
using namespace std;
int main(){
int n,aim;
cin>>n>>aim;
long long arr[n];
for(int i=0;i<n;i++){
cin>>arr[i];
}
long long dp[30000];
dp[0] = 1;
for(int i=0;i<n;i++){
for(int j=1;j<=aim;j++){
if(j>=arr[i])
dp[j] = (dp[j-arr[i]]+dp[j])%1000000007;
}
}
cout<<dp[aim]%1000000007;
return 0;
} # -*- coding: utf-8 -*- # !/usr/bin/python3 import sys while True: s = sys.stdin.readline().strip() if s == '': break else: n, t = s.split() n = int(n) t = int(t) arr = list(map(int, input().split())) arr = sorted(arr) res = [0 for i in range(t + 1)] res[0] = 1 for i in arr: if i > t: break for j in range(i, t + 1): res[j] = res[j] + res[j - i] # 输出一个整数,表示换钱的方法数对10 ^ 9 +7取模后的答案。 print(res[t] % (pow(10, 9) + 7)) ''' 解题思路: 动态规划核心状态转移方程式 f(n) = f(n - arr[0]) + f(n - arr[1]) + f(n - arr[2]) + ... + f(n - arr[i]) i为arr的长度 对于组成n的情况,每个arr[i]元与f(n - arr[i])都可以组成一个n,所以把每种f(n - arr[i])的种类数 相加,就找出了arr能组成n的种类。递归计算会重复计算f(n - arr[i]),运用斐波那契数列类似的方法, 从0开始遍历,重复利用计算过的f(n - arr[i])。结果数值会过大,题目要求输出对10 ^ 9 +7取模后的答案。 '''
// dp
#include <bits/stdc++.h>
using namespace std;
int main()
{
// 输出并创建数组
int n,aim;
cin>>n>>aim;
vector<int>arr(n,0);
for(int i=0;i<n;++i){
cin>>arr[i];
}
int M=1e9+7; // 定义模数
vector<int>dp(aim+1,0);
dp[0]=1; // 组成0元的个数
for(int i=0;i<n;++i){
for(int j=arr[i];j<=aim;++j){
dp[j]=(dp[j]+dp[j-arr[i]])%M;
}
}
cout<<dp[aim]<<endl;
return 0;
} import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int aim = sc.nextInt();
int[] nums = new int[n];
for(int i=0;i<n;i++){
nums[i] = sc.nextInt();
}
//一维dp
int[] dp = new int[aim+1];
dp[0] = 1;
for(int i=0;i<n;i++){
for(int j=nums[i];j<=aim;j++){
dp[j] = (dp[j] + dp[j-nums[i]]) % 1000000007;
}
}
System.out.println(dp[aim]);
/**
二维dp
int[][] dp = new int[n+1][aim+1];
dp[0][0] = 1;
for(int i=1;i<=n;i++){
dp[i][0] = 1;
for(int j=1;j<=aim;j++){
//每个金额的货币,有取和不取两种选择。
dp[i][j] = (dp[i-1][j] + (j>=nums[i-1]?dp[i][j-nums[i-1]]:0)) % 1000000007;
}
}
System.out.println(dp[n][aim]);
*/
}
} def count_way(arr, n):
# 第0位是辅助位,代表面额数刚好等于金钱数的一种情况
dp = [1] + [0]*n # 不用任意面额的组合数
for num in arr:
for j in range(num, n+1):
dp[j] += dp[j-num]
return dp[-1]%(1000000007)
_,n = list(map(int, input().split(' ')))
arr = list(map(int, input().split(' ')))
print(count_way(arr, n)) 同样是动态规划,python比其他语言慢了好多