SDUT 2019 级程序设计基础(B)II 实验4--递归

6月4日下午刚睡完午觉,下午没课赶紧把递归搞完吧,看情况状态好再打点贪心,多留时间给DP毕竟那才是重头,10号前应该能完成,祝看过此博客的期末都AK~
题目传送门

4-1计算组合数

很无脑的题,题目让你干啥你就干啥呗,表达式写出来就行了,计算都是电脑的事情,递归就是这么暴力。

#include 
#include 

int c(int n,int m)
{
    if(m==0||n==1||m==n) return 1;
    return c(n-1,m-1)+c(n-1,m);
}

int main()
{
    int n,m,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&m);
        printf("%d\n",c(n,m));
    }
    return 0;
}

4-2神奇的函数

比上题还方便 伪代码都有了 复制粘贴微改一下就行

#include 
#include 

int F(int n,int m) {
    if (n == 1 || m == 1)
        return  1;
    else
        return F(n-1, m) + F(n, m-1);
}
int main()
{
    int n,m;

    while(~scanf("%d %d",&n,&m))
    {
        printf("%d\n",F(n,m));
    }
    return 0;
}

4-3喵帕斯之天才算数少女

#include 
#include 

int F(int m,int n) {
    if ( m == 0)
        return  n+1;
    else if(m>0&&n==0)
        return F(m-1, 1);
    else return F(m-1,F(m,n-1));
}
int main()
{
    int n,m;

    while(~scanf("%d %d",&n,&m))
    {
        printf("%d\n",F(n,m));
    }
    return 0;
}

4-4汉诺塔

汉诺塔问题:

汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?

分析:

图片均引用自网络

先看n=3的汉诺塔:

如果再加一个盘:
SDUT 2019 级程序设计基础(B)II 实验4--递归_第1张图片
可以如此模拟:

将上面过程一般化,我们定义三个柱子的类型分别为出发柱、目标柱、缓存柱,注意柱子类型是可以不断变化的
那么把n个柱子从出发柱移动到目标柱分为三步骤:
1.把上面n-1个柱子从出发柱移动到缓存柱。
2.把第n个柱子移动到目标柱。
3.把缓存柱的n-1个柱子移动到目标柱。
其中,第一步的把n-1个柱子从出发柱移动到缓存柱也可以看成一次更小规模的汉诺塔,即原来的缓存柱变成了目标柱,原来的目标柱变成了缓存柱。这种把一个问题不断拆成更小规模的相同问题就是一种递归的思想,下面看本题代码:

#include 
#include 

void move(int n,char from,char buffer,char to)//from是出发柱,buffer是缓存柱,to是目标柱
{
    if(n==1){
        printf("Move disk %d from %c to %c\n",n,from,to);
    }
    else
    {
        move(n-1,from,to,buffer);//第一次递归原来的目标柱变成了缓存柱,缓存柱变成了目标柱
        printf("Move disk %d from %c to %c\n",n,from,to);//输出一下当前怎么动
        move(n-1,buffer,from,to);//和上面同理
    }
}

int main()
{
    int n;
    scanf("%d",&n);
    move(n,'A','B','C');
    return 0;
}

4-5青蛙过河

书上很详细~

#include 
#include 

int jump(int s,int y)
{
    int k;
    if(s==0)

        k=y+1;
    else
        k=2*jump(s-1,y);
    return k;
}

int main()
{
    int s,y;
    while(~scanf("%d %d",&s,&y))
    {
        printf("%d\n",jump(s,y));
    }
    return 0;
}

4-6数据结构实验之排序八:快速排序

要不是考试不能用STL

#include 
#include 

int a[100010];
void sort(int l,int r)
{
    int x=a[l],i=l,j=r;
    if(l>=r) return;
    while(i<j)
    {
        while(a[j]>=x&&i<j) j--;
        a[i]=a[j];
        while(a[i]<=x&&i<j) i++;
        a[j]=a[i];
    }
    a[i]=x;
    sort(l,i-1);
    sort(i+1,r);
}

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        sort(0,n-1);
        for(int i=0;i<n;i++)
        {
            if(i==n-1) printf("%d\n",a[i]);
            else printf("%d ",a[i]);
        }
    }
    return 0;
}

4-7第X大的数

就是每次只进一半的快排

#include 
#include 

int a[100010];
int find(int l,int r,int k)
{
    int x=a[l],i=l,j=r;
    while(i<j)
    {
        while(a[j]<=x&&i<j) j--;
        a[i]=a[j];
        while(a[i]>=x&&i<j) i++;
        a[j]=a[i];
    }
    a[i]=x;
    if(i==k) return a[i];
    if(i>k)
    find(l,i-1,k);
    else
    find(i+1,r,k);
}

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        int m;
        scanf("%d",&m);
        while(m--)
        {
            int k;
            scanf("%d",&k);
            printf("%d\n",find(0,n-1,k-1));
        }
    }
    return 0;
}

4-8 M–二分查找

#include 
#include 

int a[3000010];
int find(int l,int r,int k)
{
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(a[mid]==k)
            return mid;
        else if(a[mid]<k)
            l=mid+1;
        else
            r=mid-1;
    }
    return -1;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%d",&a[i]);
    int m;
    scanf("%d",&m);
    while(m--)
    {
        int k;
        scanf("%d",&k);
        printf("%d\n",find(1,n,k));
    }
    return 0;
}

4-9第k小的数

#include 
#include 

int a[900010];
int find(int l,int r,int k)
{
    int x=a[l],i=l,j=r;
    while(i<j)
    {
        while(a[j]>=x&&i<j)
            j--;
        a[i]=a[j];
        while(a[i]<=x&&i<j)
            i++;
        a[j]=a[i];
    }
    a[i]=x;
    if(i==k)
        return a[i];
    if(i>k)
        find(l,i-1,k);
    else
        find(i+1,r,k);
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        scanf("%d %d",&n,&k);
        for(int i=0; i<n; i++)
            scanf("%d",&a[i]);
        printf("%d\n",find(0,n-1,k-1));
    }
    return 0;
}

4-10全排列问题

#include 
#include 
int a[11];
void swap(int *p,int *q)
{
    int t=*p;
    *p=*q;
    *q=t;
}
//下面两个函数此题没用到,用于有序输出全排列
void cr(int l,int r)
{
    if(l>=r) return;
    int t=a[r];
    for(int i=r;i>l;i--)
    {
        a[i]=a[i-1];
    }
    a[l]=t;
}
void cz(int l,int r)
{
    if(l>=r) return;
    int t=a[l];
    for(int i=l;i<r;i++)
    {
        a[i]=a[i+1];
    }
    a[r]=t;
}
void prem(int k,int n)
{
    if(k==n)
    {
        for(int i=0;i<=n;i++)
        {
            if(i==n) printf("%d\n",a[i]);
            else printf("%d,",a[i]);
        }
    }
    else
    {
        for(int i=k;i<=n;i++)
        {
            swap(&a[k],&a[i]);
            prem(k+1,n);
            swap(&a[k],&a[i]);
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        prem(0,n-1);
    }
    return 0;
}

小结

如果你愿意一层一层一层地拨开我的心,你会发现,你会讶异,这道题最压抑最深处的秘密~~ 解递归问题就像剥洋葱,边剥边哭。递归最重要的就是找规律,考虑问题的时候先从最简单的情况考虑,然后逐渐复杂,寻找复杂问题和简单问题的联系,往往简单问题就是递归边界。

你可能感兴趣的:(程序设计基础(B)II)