题解 | #换钱的最少货币数#
换钱的最少货币数
https://www.nowcoder.com/practice/4e05294fc5aa4d4fa8eacef2e606e5a8
方法一
参考动态规划的意义是什么? - 阮行止的回答中1. 从一个生活问题谈起
的思路。
#include<iostream> #include<vector> using namespace std; int getMinCoin(vector<int>& arr, int aim){ if(arr.empty() || aim<0){ return -1; } else if(aim==0) return 0; int n=arr.size(); //记录凑出0~aim元时,需要的最少货币数。 //INT16_MAX表示凑不出来 vector<int> dp(aim+1,INT16_MAX); dp[0]=0;//凑出0元,货币数是0 for(int i=1;i<=aim;i++){ for(int j=0;j<n;j++){ //i-arr[j]>=0.表示当前货币i可以使用arr[j]换 if((i-arr[j])>=0) { //dp[i-arr[j]]表示换了后的剩余货币数 //想象成dp[i-arr[j]]已是最优解, //则换i元所需的货币数为i-arr[j]所需货币数+1 dp[i] = min(dp[i],dp[i-arr[j]]+1); } } } //说明给定的货币都换不出来 if(dp[aim]==INT16_MAX) return -1; return dp[aim]; } int main() { int n,aim; cin>>n>>aim; vector<int> arr(n); for(auto i=0;i<n;i++){ cin>>arr[i]; } auto res=getMinCoin(arr,aim); cout<<res<<endl; return 0; }
方法二
根据左程云书中原问题的经典动态规划方法
。
#include<iostream> #include<vector> using namespace std; //使用二维dp矩阵的解法 int getMinCoin(vector<int>& arr, int aim) { if (arr.empty() || aim < 0) { return -1; } else if (aim == 0) return 0; int n = arr.size(); //货币的种类数 vector<vector<int>> dp(n,vector<int>(aim+1)); //只使用dp[0]货币时,记录凑出0~aim元时, //需要的最少货币数,存入dp[0][j]。 //INT16_MAX表示凑不出 int maxV=INT16_MAX; for(int j=1;j<(aim+1);j++){ dp[0][j]=maxV; //j-arr[0]>=0,表示当前价值j可以使用arr[0]凑 //dp[0][j-arr[0]]!=INT16_MAX,表示使用arr[0]能凑出j-arr[0] if((j-arr[0])>=0 && dp[0][j-arr[0]]!=maxV){ //只需在dp[0][j-arr[0]]使用的货币数上加1 dp[0][j]=dp[0][j-arr[0]]+1; } } int cost=0; for (int i = 1; i < n; i++) { //由于dp[i][0]表示aim=0时需要的货币数,因此全为0。 //所以j从1开始 for (int j = 1; j < (aim+1); j++) { cost=maxV; if((j-arr[i])>=0 && dp[i][j-arr[i]]!=maxV){ //cost表示使用了一个arr[i]货币,换出j价值所需的货币数 cost=dp[i][j-arr[i]]+1; } //dp[i-1][j]表示不使用arr[i]货币时,换出j价值所需的货币数 //当不用arr[i]货币就能换出j价值货币时, //所需的货币数小于使用了的,则不用arr[i]货币 dp[i][j]=min(dp[i-1][j],cost); } } //说明给定的货币都换不出来 if (dp[n-1][aim] == maxV) return -1; return dp[n-1][aim]; } int main() { int n, aim; cin >> n >> aim; vector<int> arr(n); for (auto i = 0; i < n; i++) { cin >> arr[i]; } auto res = getMinCoin(arr, aim); cout << res << endl; return 0; }
方法三
根据左程云书中原问题在动态规划基础上的空间压缩方法
。
#include<iostream> #include<vector> using namespace std; //使用一维dp矩阵的解法 int getMinCoin(vector<int>& arr, int aim) { if (arr.empty() || aim < 0) { return -1; } else if (aim == 0) return 0; int n = arr.size(); //货币的种类数 //对dp进行滚动更新,起始时dp[j]代表只使用arr[0]货币时, //记录凑出j元时,需要的最少货币数。 //终止时,dp[j]代表使用了arr[0~n-1]货币凑出j元时,需要的最少货币数。 vector<int> dp(aim+1); //INT16_MAX表示凑不出 int maxV=INT16_MAX; for(int j=1;j<(aim+1);j++){ dp[j]=maxV; //j-arr[0]>=0,表示当前价值j可以使用arr[0]凑 //dp[j-arr[0]]!=INT16_MAX,表示使用arr[0]能凑出j-arr[0] if((j-arr[0])>=0 && dp[j-arr[0]]!=maxV){ //只需在dp[j-arr[0]]使用的货币数上加1 dp[j]=dp[j-arr[0]]+1; } } int cost=0; for (int i = 1; i < n; i++) { //由于dp[0]表示aim=0时需要的货币数,因此全为0。 //所以j从1开始 for (int j = 1; j < (aim+1); j++) { cost=maxV; if((j-arr[i])>=0 && dp[j-arr[i]]!=maxV){ //cost表示使用了一个arr[i]货币,换出j价值所需的货币数 cost=dp[j-arr[i]]+1; } //右侧的dp[j]未更新,表示不使用arr[i]货币时,换出j价值所需的货币数 //当不用arr[i]货币就能换出j价值货币时, //所需的货币数小于使用了的,则不用arr[i]货币 dp[j]=min(dp[j],cost); } } //说明给定的货币都换不出来 if (dp[aim] == maxV) return -1; return dp[aim]; } int main() { int n, aim; cin >> n >> aim; vector<int> arr(n); for (auto i = 0; i < n; i++) { cin >> arr[i]; } auto res = getMinCoin(arr, aim); cout << res << endl; return 0; }