换零钱

来源:互联网 发布:apache显示目录列表 编辑:程序博客网 时间:2024/06/11 16:20

题目描述

想兑换100元钱,有1,2,5,10四种钱,问总共有多少兑换方法

递归解法

#include<iostream>using namespace std; const int N = 100;  int dimes[] = {1, 2, 5, 10};  int arr[N+1] = {1};  int coinExchangeRecursion(int n, int m) //递归方式实现,更好理解{    if (n == 0)   //跳出递归的条件    return 1;    if (n < 0 || m == 0)      return 0;   return (coinExchangeRecursion(n, m-1) + coinExchangeRecursion(n-dimes[m-1], m));    //分为两种情况:换取当前面值的情况 + 没有换取当前面值的情况}int main(){  int num=coinExchangeRecursion(N, 4);   cout<<num<<endl;   return 0; }

非递归解法

#include<iostream>using namespace std; const int N = 100;  int dimes[] = {1, 2, 5, 10};  int arr[N+1] = {1};  int coinExchange(int n)   //非递归实现{    int i, j;    //i从0 ~ 3 因为每个arr[j]都要有一次是假设兑换了dimes[i],所以我们要遍历一次  for (i = 0; i < sizeof(dimes)/sizeof(int); i++)  {      for (j = dimes[i]; j <= n; j++)         //求,arr[j]的时候,可以看出arr[j] = arr[j] + arr[j-dimes[i]],      //对应着上面的递归方式:arr[j]就是coinExchangeRecursion(n, m-1),      //arr[j-dimes[i]]就是coinExchangeRecursion(n-dimes[m-1], m)      arr[j] += arr[j-dimes[i]];    }    return arr[n];  }  int main(){  int num2=coinExchange(N);   cout<<num2<<endl;   return 0;}

下面写法更容易理解一些:

int coinExchange(int n)   //非递归实现{      int i, j;      for(i=1; i<=n; i++)    {        for (j=0; j<sizeof(dimes)/sizeof(int); i++)        {            if (i>=dimes[j])                arr[i] += arr[i-dimes[j]]        }    }    return arr[n];  }

方法总结

动态规划的经典之处把大问题分解成几个小问题解决 
递归算法: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)

#include<iostream>#include<vector> //std::vector#include <algorithm> //std::countusing namespace std; const int N = 100;  int dimes[] = {1, 2, 5, 10};  int arr[N+1] = {1}; vector<int> vv; int coinExchangeRecursion(int n, int m) //递归方式实现,更好理解{      if (n == 0) {        int i;        for (i = 0; i < sizeof(dimes)/sizeof(int); i++) {            int cnt = count(vv.begin(), vv.end(), dimes[i]);            cout << dimes[i] << ": " << cnt << "\t";        }        cout  << endl;        return 1;      }   //跳出递归的条件    if (n < 0 || m == 0)      return 0;    vv.push_back(dimes[m-1]);    int yes = coinExchangeRecursion(n-dimes[m-1], m);    vv.pop_back();    int no = coinExchangeRecursion(n, m-1);    return (no+yes);      //分为两种情况,如果没有换当前硬币,那么是多少?加上,如果换了当前硬币,总值减少,此时又是多少种兑换方法?}int coinExchange(int n)   //非递归实现{      int i, j;      for (i = 0; i < sizeof(dimes)/sizeof(int); i++)   //i从0 ~ 3 因为每个arr[j]都要有一次是假设兑换了dimes[i],所以我们要遍历一次    {          for (j = dimes[i]; j <= n; j++)               //求,arr[j]的时候,可以看出arr[j] = arr[j] + arr[j-dimes[i]],            //对应着上面的递归方式:arr[j]就是 coinExchangeRecursion(n, m-1),            //arr[j-dimes[i]]就是coinExchangeRecursion(n-dimes[m-1], m)            arr[j] += arr[j-dimes[i]];      }      return arr[n];  }  int main(int argc, char *argv[]){    int num=coinExchangeRecursion(N, 4);     cout<<num<<endl;     int num2=coinExchange(N);     cout<<num2<<endl;     return 0; }

参考:

  • http://www.tuicool.com/articles/VBreAnY
  • http://taop.marchtea.com/02.05.html
  • 动态规划:从新手到专家