3.递归、递推

首先谈谈C++ STL(Standard Template Library)中常用几种数据类型

1. list:双向链表  、基本等同数组   #include<list>    

2.vector:向量、基本等同个数组、和list区别在于存储空间连续   #include<vector>

3.queue: 队列、先进先出链表   #include<queue>    

4.stack :栈、后进先出链表    #include<stack >

5.priority_queue:优先队列、排好序的队列   #include<priority_queue>

6.set:集合、排好序的去重的数组   #include<set>

7.map:python中的字典,自动根据关键字排好序   #include<map>

8.其他..... 待了解

参考博客:

      c++STL容器(map,set,vector,stack,queue)

      C++list的使用总结及常用list操作

较常用的是vector、set和map,这些再和结构体组合起来用,美滋滋。自己实验了一下vector实现图邻接链表,map的基本操作

#include<iostream>
#include<vector>
#include<map>
using namespace std;

typedef struct node {
    int data;
    vector<int> index;

};

int main()
{

    struct node graph[100];//创建

    int i,j;
    for(i=0;i<4;i++)  //输入
    {
        graph[i].data=i;
    }
    int v1,v2;
    for(i=0;i<4;i++)
    {
        cout<<"请输入边v1-v2:";
        cin>>v1>>v2;
        graph[v1].index.push_back(v2);
        graph[v2].index.push_back(v1);
    }

    for(i=0;i<4;i++)//输出
        {
            cout<<"顶点"<<graph[i].data<<": ";
            for(int j=0;j<graph[i].index.size();j++)
                cout<<graph[i].index[j]<<' ';
            cout <<endl;
        }

    // map测试
    map<int,string>test;
    test.insert(pair<int, string>(1, "student_one"));
    test.insert(pair<int, string>(2, "student_two"));
    test.insert(pair<int, string>(3, "student_three"));
    map<int,string>::iterator iter;
    for(iter=test.begin();iter!=test.end();iter++)
        cout<<iter->first<<" "<<iter->second<<endl;

    map<string,string>t;
    t["a"]= "student_one";
    t["b"] ="student_two";
    t["c"]= "student_three";
   // map<int,string>::iterator i;
    //for(int i=0;i<2;i++)
        cout<<t["a"]<<endl<<t["b"]<<endl;
    return 0;
}

效果如下:

 

进入正题

-------------------------------------------------------------我是分割线-----------------------------------------------------------------

递归:定义:函数自己调用自己。看完感受:啥玩意?

求阶乘那种简单问题看了等于没看。变换一下又蒙了。先看个题

P1192 台阶问题

这个题递归、递推都能实现。

题解:我要走到第n个台阶,要么从n-1走一步到,或者从n-2跨两阶到,。。。。从n-k阶跨k个台阶到。

也就是说走到n的方案数 S(n)= S(n-1)+ S(n-1)+.....+ S(n-k)(此处需要理解)

这么理解:

假设k=2,当n=1的时候可以从第0个台阶走1步   1种方案。

依次递推:n=2    从0走2步和从1走1步; S(2) = S(1)+S(0) = 1+1 =2;

                  n=3    从1走2步和从2走1步; S(3) = S(2)+S(1) = 2+1 =3;

                                                。。。。。。。。。。。。。

递归代码就可以这么写:

#include<bits/stdc++.h>
using namespace std;
int n,k;
int digui (int n){
    if(n==0) return 1;
    int sum=0;
    for(int i=1;i<=k;i++)
    {
        if(n-i<0) break;
        sum=(sum + digui(n-i))%100003;//此处为上面推导的公式
    }

    return sum%100003;
}
int main(){


    cin>>n>>k;
    int sum = digui(n);
    cout<<sum<<endl;
    return 0;
}

恭喜:20分到手!   4804ms,已经很仁慈了

我感觉自己被骗了,说好的递归呢??

仔细想想,中间好像存在很多重复计算的过程。

比如n = 10, k=3;

n = 10 时,我需要递归 n=9,n=8,n=7

n = 9 时,我需要递归 n=8,n=7,n=6

n = 8 时,我需要递归 n=7,n=6,n=5

       .。。。。。。。。。。

太多重复了!!!!!

我能不能只算一次呢?     状态数组说:没问题啊

思路很简单:每次算之后我把结果保存起来,下次到了先看一下算没算过,算过的话就直接取结果赶紧回家吧。

#include<bits/stdc++.h>//万能库
using namespace std;
int n,k;
int s[100010];
int digui (int n){
    if(n==0) return 1;
    if(s[n]) return s[n];//算过了,给你数据,赶紧回家吧
    int sum=0;
    for(int i=1;i<=k;i++)
    {
        if(n-i<0) break;
        s[n]=(s[n] + digui(n-i))%100003;
    }

    return s[n]%100003;
}
int main(){


    cin>>n>>k;
    int sum = digui(n);
    cout<<sum<<endl;
    return 0;
}

大神看了一下,你这个竟然过了??  10^4 * 10^3,很容易超啊

偷偷告诉你,时间可以降到 10^4,没错,一重循环就够了!

 

递推闪亮登场~

思想很简单:用一个变量保存前n-k到n的和,然后从前往后,每加一个数我就踢掉前面一个。

比如  i从 n-2到n-1,踢掉S(n-2-k),加上S(n-1),这样保证永远是n到n-k,k个结果之和。

有一篇通熟易懂的文章:漫画:什么是动态规划?

#include<bits/stdc++.h>
using namespace std;
int n,k;
int dp[100010];
int main()
{
    int n,k,i,j;
    cin>>n>>k;
    //for(i=1;i<=k;i++)
        dp[0]=1;
        int sum=dp[0];
    for(i=1;i<=n;i++)
        {
            if(i<k)
                {dp[i]= sum;sum=(sum+dp[i])%100003;}  //最前面不足K个时,不踢
            else
                {dp[i]= sum;sum=(sum+dp[i]+100003-dp[i-k])%100003;}//加一个踢一个,+100003是保证不出现负数
        }

    cout<<dp[n]<<endl;
    return 0;
}

 

总结一下递推和递归:

递归:从后往前找解,也就是循环的另外一种实现手段,很暴力,当问题没法确定循环轮数或次数时考虑用递归。

递推:从前往后推导,跟核心公式跟递归一样,只不过保存每一次结果,时间一般比递归快,典型空间换时间。

其实递推和递归都是将问题分解为每一个子问题

基本就思考三个点:结束条件、每一次递归要解决的问题、每一步递归的意义

重点要理解递归执行的全部过程。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值