码迷,mamicode.com
首页 > 其他好文 > 详细

理解递归函数,和动态规划

时间:2015-05-13 16:22:11      阅读:96      评论:0      收藏:0      [点我收藏+]

标签:

    作为一个CS学生,必须理解递归函数。这学期的Foundation of Computer里有一章讲到了递归,突然间有了新感悟。

    以前理解递归,总会在脑海里模拟递归过程,直到返回为止。但常常内存不够,大脑宕机……T.T

------------------------------------------------------------------------------------------------------------------------------------

    举两个例子,一下就明白了:

    a[n] = a[n-1] + 1

    a[0] = 0;

    等差数列!…………一个数的值等于前一个数加1.再加上个初始条件。

 

    F[n] = F[n-1] + F[n-2]

    F[0] = 0  F[1] = 1

    Fibonacci 数列 ……… 这个数等于前两个数之和。初始条件是前两个数。

 

    还有高中那些个数列啊什么的

    a[n] = Aa[n-1] + B , a[0] = xxx。依稀记得求个特征值什么的。

    我们知道了递归,其实是定义相关关系。

    

    实践一下:

一、求a[1...n]的最大值

    定义max(n)是数组的最大值(注意它虽然是一个递归函数,但实际还是一个值,和前面提到的例子中的F[n],a[n]是一样样的)

    max(n) = a[n] 和 max(n-1) 两数较大的那一个

    max(1) = a[1]

    第一:定义相关关系。

    第二:定义截至条件。

    相关代码:

int max( int a[], int n){
    if( n == 0 ) return a[0];    
    return a[n] > max( a, n-1 )? a[n]:max(a,n-1);
} 

 

二、生成组合数

 a1a2......an选m个数,C(a1a2....an,m)代表选m个数的结果

    C(a1...an,m) = a1C(a2...an,m-1) + a2C(a3...an,m-1)  +...+ a[n-m+1]C(an-m+2...an,m-1)

    截至条件:没有可能时返回,即, 数列长度小于m或者m<=0

    举例来说: 1 2 3 4选3个数的组合,等于 1{2 3 4 选2个数的组合} + 2{3 4 选2个数的组合} + 3 { ... 这里没有选择就返回了 }

    其中

    2 3 4选2个数的组合,等于2{3 4选1个数的组合} + 3{4 选1个数的组合}

    3 4选2个数的组合,等于3{4 选1个数的组合}

    ……(不展开了)

    所以1 2 3 4选3个数的组合等于

    1{2 3,2 4} + 2{ 3 4 } = 1 2 3 + 1 2 4 + 2 3 4

    相关代码:

template<typename T> 
void PrintVV(vector<vector<T>> v){
    for (auto it : v){
        for (auto it2 : it){
            printf("%d ", it2);
        }
        printf("\n");
    }
}


void comb(vector<vector<int>> &vviInsert, vector<int> &a, int m, int pos/* start pos */){
    if (a.size() - pos < m || m <= 0){
        return;
    }
    if (!vviInsert.size()){
        for (int i=0; a.size()- i >= m; i++){
            vviInsert.push_back(vector<int>({ a[i] }));
            comb(vviInsert, a, m-1, i + 1);
        }
    } else{
        vector<int> aVi = vviInsert.back();
        vviInsert.pop_back();
        for (int i=pos; a.size() - i >= m; i++){
            aVi.push_back(a[i]);
            vviInsert.push_back(aVi);
            aVi.pop_back();
            comb(vviInsert, a, m-1, pos + 1);
        }
    }
}



int main(int argc, char *argv[])
{
    vector<int> viA;
    vector<vector<int>> vviResult;
    viA.assign({ 1, 2, 3,4 });
    comb(vviResult, viA, 2, 0);
    PrintVV(vviResult);
    system("pause");
    return 0;
}

 

    总结一下,设计递归函数一要理出相关关系。二要设置截至条件。

    多说一句,相关关系实际是问题与子问题的关系,可能会重复计算,比如在生成组合数的例子中,我们看到绿色部分被重复计算了两次。而在寻找Fibonacci数中,我们知道重复计算量会更大。对于这种需要重复计算的子问题,可以把重复计算子问题的答案储存起来,使用时查询,无需计算。这就是动态规划的思想。

    

理解递归函数,和动态规划

标签:

原文地址:http://www.cnblogs.com/MyloverisU/p/4500471.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!