想兑换100元钱,有1,2,5,10四种钱,问总共有多少兑换方法?
递归解法
1 #include<iostream> 2 using namespace std; 3 4 const int N = 100; 5 int dimes[] = {1, 2, 5, 10}; 6 int arr[N+1] = {1}; 7 8 int coinExchangeRecursion(int n, int m) //递归方式实现,更好理解 9 { 10 if (n == 0) //跳出递归的条件 11 return 1; 12 if (n < 0 || m == 0) 13 return 0; 14 15 return (coinExchangeRecursion(n, m-1) + coinExchangeRecursion(n-dimes[m-1], m)); 16 //分为两种情况:换取当前面值的情况 + 没有换取当前面值的情况 17 } 18 19 int main() 20 { 21 int num=coinExchangeRecursion(N, 4); 22 cout<<num<<endl; 23 24 return 0; 25 26 }
非递归解法
1 #include<iostream> 2 using namespace std; 3 4 const int N = 100; 5 int dimes[] = {1, 2, 5, 10}; 6 int arr[N+1] = {1}; 7 8 int coinExchange(int n) //非递归实现 9 { 10 int i, j; 11 //i从0 ~ 3 因为每个arr[j]都要有一次是假设兑换了dimes[i],所以我们要遍历一次 12 for (i = 0; i < sizeof(dimes)/sizeof(int); i++) 13 { 14 for (j = dimes[i]; j <= n; j++) 15 //求,arr[j]的时候,可以看出arr[j] = arr[j] + arr[j-dimes[i]], 16 //对应着上面的递归方式:arr[j]就是coinExchangeRecursion(n, m-1), 17 //arr[j-dimes[i]]就是coinExchangeRecursion(n-dimes[m-1], m) 18 arr[j] += arr[j-dimes[i]]; 19 20 } 21 return arr[n]; 22 } 23 24 25 int main() 26 { 27 int num2=coinExchange(N); 28 cout<<num2<<endl; 29 30 return 0; 31 }
方法总结
动态规划的经典之处把大问题分解成几个小问题解决
递归算法:100元的换法:零钱中有此面值与零钱中没此面值的两种情况,注意递归结束的条件
非递归算法:换100的零钱,那么先从换1、2、……的零钱算起,这个算法,最好转换成台阶走法的问题来理解
仔细推理可以看出arr[j] = arr[j-dimes[0]] + arr[j-dimes[1]] + arr[j-dimes[2]] + arr[j-dimes[3]] (j-dimes[i]>=0)
1 #include<iostream> 2 #include<vector> //std::vector 3 #include <algorithm> //std::count 4 using namespace std; 5 6 const int N = 100; 7 int dimes[] = {1, 2, 5, 10}; 8 int arr[N+1] = {1}; 9 vector<int> vv; 10 11 int coinExchangeRecursion(int n, int m) //递归方式实现,更好理解 12 { 13 if (n == 0) { 14 int i; 15 for (i = 0; i < sizeof(dimes)/sizeof(int); i++) { 16 int cnt = count(vv.begin(), vv.end(), dimes[i]); 17 cout << dimes[i] << ": " << cnt << " "; 18 } 19 cout << endl; 20 return 1; 21 } //跳出递归的条件 22 if (n < 0 || m == 0) 23 return 0; 24 vv.push_back(dimes[m-1]); 25 int yes = coinExchangeRecursion(n-dimes[m-1], m); 26 vv.pop_back(); 27 int no = coinExchangeRecursion(n, m-1); 28 return (no+yes); 29 //分为两种情况,如果没有换当前硬币,那么是多少?加上,如果换了当前硬币,总值减少,此时又是多少种兑换方法? 30 } 31 32 int coinExchange(int n) //非递归实现 33 { 34 int i, j; 35 for (i = 0; i < sizeof(dimes)/sizeof(int); i++) //i从0 ~ 3 因为每个arr[j]都要有一次是假设兑换了dimes[i],所以我们要遍历一次 36 { 37 for (j = dimes[i]; j <= n; j++) 38 //求,arr[j]的时候,可以看出arr[j] = arr[j] + arr[j-dimes[i]], 39 //对应着上面的递归方式:arr[j]就是 coinExchangeRecursion(n, m-1), 40 //arr[j-dimes[i]]就是coinExchangeRecursion(n-dimes[m-1], m) 41 arr[j] += arr[j-dimes[i]]; 42 } 43 return arr[n]; 44 } 45 46 int main(int argc, char *argv[]) 47 { 48 int num=coinExchangeRecursion(N, 4); 49 cout<<num<<endl; 50 51 int num2=coinExchange(N); 52 cout<<num2<<endl; 53 54 return 0; 55 }
参考链接:
http://www.cnblogs.com/sdjl/articles/1274312.html
https://www.tuicool.com/articles/VBreAnY