题目描述
给定数组arr,设数组长度为n,arr中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个整数aim,代表要找的钱数,求换钱的方法数有多少种。由于方法的种数比较大,所以要求输出对10^9+7进行取模后的答案。
输入描述:
输出包括两行,第一行包括两个整数n(0≤n≤1000)和aim(0≤aim≤20000)。第二行包含n个整数,表示arr数组(1≤arri≤1e9)。
输出描述:
输出一个整数,表示换钱的方法数对10^9+7取模后的答案。
示例1
输入
4 15 5 10 25 1
输出
6
示例2
输入
5 1000
2 3 5 7 10
输出
20932712
备注:
时间复杂度O(N∗aim),空间复杂度O(aim)。
//方法1:暴力枚举
//运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。
//case通过率为0.00% 示例1可通过,vs2017
#include<bits/stdc++.h>
using namespace std;
const int number=1000000007;
int process(vector<int>& arr,int i,int rest){
if(i==arr.size()){
return (rest==0 ? 1 : 0);
}
int res=0;
for(int k=0;k*arr[i]<=rest;k++){
res+=process(arr,i+1,rest-k*arr[i]);
res%=number;
}
return res;
}
int main(){
int n,aim;
cin>>n>>aim;
vector<int> arr(n);
for(int i=0;i<n;i++){
cin>>arr[i];
}
cout<<process(arr,0,aim)<<endl;
return 0;
}
//方法2:记忆化搜索 ac
//O(n*aim^2) O(n*aim)
#include<bits/stdc++.h>
using namespace std;
const int number=1000000007;
vector<vector<int>> memo;
int process(vector<int>& arr,int i,int rest){
if(i==arr.size()){
return (rest==0 ? 1 : 0);
}
if(memo[i][rest]!=-1){
return memo[i][rest];
}
int res=0;
for(int k=0;k*arr[i]<=rest;k++){
res+=process(arr,i+1,rest-k*arr[i]);
res%=number;
}
memo[i][rest]=res;
return res;
}
int main(){
int n,aim;
cin>>n>>aim;
vector<int> arr(n);
for(int i=0;i<n;i++){
cin>>arr[i];
}
memo=vector<vector<int>>(n,vector<int>(aim+1,-1));
cout<<process(arr,0,aim)<<endl;
return 0;
}
//方法3:动态规划 O(n*aim) O(n*aim)
//dp[i][j]的定义是在使用arr[0..i]货币的情况下,组成钱数j有多少种方法
#include<bits/stdc++.h>
using namespace std;
const int number=1000000007;
int main(){
int n,aim;
cin>>n>>aim;
vector<int> arr(n);
for(int i=0;i<n;i++){
cin>>arr[i];
}
vector<vector<int>> dp(n,vector<int>(aim+1,0));
for(int i=0;i<n;i++){
dp[i][0]=1; //对于钱数为0,有1种方法
}
for(int j=1;j*arr[0]<=aim;j++){ //使用钱币arr[0]可以找开的钱数,都有这一种方法
dp[0][j*arr[0]]=1;
}
for(int i=1;i<n;i++){
for(int j=1;j<=aim;j++){
dp[i][j]=dp[i-1][j]; //不使用arr[i]有多少种找法
if(j-arr[i]>=0){
dp[i][j]=(dp[i][j]+dp[i][j-arr[i]])%number; //加上使用arr[i]的找法
}
}
}
cout<<dp[n-1][aim]<<endl;
return 0;
}
//方法4:优化方法3的空间
//O(n*aim) O(aim)
#include<bits/stdc++.h>
using namespace std;
const int number=1000000007;
int main(){
int n,aim;
cin>>n>>aim;
vector<int> arr(n);
for(int i=0;i<n;i++){
cin>>arr[i];
}
vector<int> dp(aim+1,0);
dp[0]=1; //对于钱数为0,有1种方法
for(int i=0;i<n;i++){
for(int j=arr[i];j<=aim;j++){
dp[j]=(dp[j]+dp[j-arr[i]])%number;
}
}
cout<<dp[aim]<<endl;
return 0;
}