zoukankan      html  css  js  c++  java
  • careercup-递归和动态规划 9.8

    9.8 给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码就是n分有几种表示法。

    解法:

    使用回溯法进行解决,实际上就是一个类似枚举的过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。

    C++实现代码:

    #include<vector>
    #include<iostream>
    using namespace std;
    
    void helper(vector<int> &denom,int target,vector<int> &path,vector<vector<int> > &res)
    {
        if(target<0)
            return;
        if(target==0)
        {
            res.push_back(path);
            return;
        }
        int i;
        for(i=0;i<(int)denom.size();i++)
        {
            path.push_back(denom[i]);
            helper(denom,target-denom[i],path,res);
            path.pop_back();
        }
    }
    
    vector<vector<int> > makeChange(vector<int> &denom,int target)
    {
        if(denom.empty())
            return vector<vector<int> >();
        vector<vector<int> > res;
        vector<int> path;
        helper(denom,target,path,res);
        return res;
    }
    
    int main()
    {
        vector<int> vec={1,2,3};
        vector<vector<int> > res=makeChange(vec,5);
        for(auto a:res)
        {
            for(auto t:a)
                cout<<t<<" ";
            cout<<endl;
        }
    }

    运行结果:

    其中存在重复的,譬如:1 1 2 1 和 2 1 1 1。虽然顺序不一样,但是表示的同样的划分。

    这是错误的,问题出在哪呢?有序和无序的区别!这个函数计算出来的组合是有序的,也就是它会认为1,2和2,1是不一样的,导致计算出的组合里有大量是重复的。那要怎么避免这个问题呢?1,5和5,1虽然会被视为不一样,但如果它们是排好序的,比如都按从大到小排序,那么就是5,1了,这时就不会重复累计组合数量。可是我们总不能求出答案之后在排序吧,多费劲。这是我们就在递归上动手脚,让它在计算的过程中就按照从大到小的币值来组合。比如,现在我拿了一个25分的硬币,那下一次可以去的币值就是25,10,5,1;如果我拿了一个10分的,下一次可以取的币值就只有10,5,1了;这样一来,就能保证,我只累计了一次,改造后的代码如下:

    #include<vector>
    #include<iostream>
    using namespace std;
    
    void helper(vector<int> &denom,int start,int target,vector<int> &path,vector<vector<int> > &res)
    {
        if(target<0)
            return;
        if(target==0)
        {   
            res.push_back(path);
            return;
        }   
        int i;
        for(i=start;i<(int)denom.size();i++)
        {   
            path.push_back(denom[i]);
         //只能从下标i和i之后的元素开始取 helper(denom,i,target
    -denom[i],path,res); path.pop_back(); } } vector<vector<int> > makeChange(vector<int> &denom,int target) { if(denom.empty()) return vector<vector<int> >(); vector<vector<int> > res; vector<int> path; helper(denom,0,target,path,res); return res; } int main() { vector<int> vec={3,2,1}; vector<vector<int> > res=makeChange(vec,5); for(auto a:res) { for(auto t:a) cout<<t<<" "; cout<<endl; } }

    运行结果:

    [root@localhost 桌面]# ./coin 
    3 2 
    3 1 1 
    2 2 1 
    2 1 1 1 
    1 1 1 1 1 

    #include<iostream>
    using namespace std;
    
    int makeChange(int n,int denom)
    {
        int next_denom=0;
        switch(denom)
        {
        case 25:
            next_denom=10;
            break;
        case 10:
            next_denom=5;
            break;
        case 5:
            next_denom=1;
            break;
        case 1:
            return 1;
        }
        int i;
        int way=0;
        for(i=0;n-i*denom>=0;i++)
        {
            way+=makeChange(n-i*denom,next_denom);
        }
        return way;
    }
    
    int main()
    {
        cout<<makeChange(100,25)<<endl;
    }
  • 相关阅读:
    (转载)Linux系统中分离线程的使用
    (转载)Vim的几种模式介绍
    (转载)Linux下检查内存泄漏、系统性能的系列工具
    (转载)Linux 僵尸进程与孤儿进程
    (转载)valgrind,好东西,一般人我不告诉他~~ 选项
    (转载)Linux进程组、作业、会话的理解
    Open a file, and then readin a file tcl tk
    save vars and arrays
    itcl class example
    constructor with args tcl tk
  • 原文地址:https://www.cnblogs.com/wuchanming/p/4150731.html
Copyright © 2011-2022 走看看