[递归专题打卡]2021 6.30-7.2

​同步于本人CSDN   https://blog.csdn.net/qq_39391544

2021/6/30

链接:https://ac.nowcoder.com/acm/problem/14310
来源:牛客网
 

★字符串逆序

输入一个字符串,长度在100以内,按相反次序输出其中的所有字符。

输入描述:

输入一个字符串

输出描述:

输出反序的字符串

示例1

输入

tsinghua

输出

auhgnist

解答:

 1 #include<stdio.h>
 2 #include<string.h>
 3 int lenth;
 4 void Output(char* a,int n)
 5 {
 6     if(n==lenth)
 7         return;
 8     Output(a,n+1);
 9     printf("%c",a[n]);
10 }
11 int main()
12 {
13     char a[101];
14     scanf("%s",a);
15     lenth=strlen(a);
16     Output(a,0);
17     return 0;
18 }

 

 

 

链接:https://ac.nowcoder.com/acm/problem/14320
来源:牛客网
 

★杨辉三角

杨辉三角形又称Pascal三角形,它的第i+1行是(a+b)i的展开式的系数。

它的一个重要性质是:三角形中的每个数字等于它两肩上的数字相加。

下面给出了杨辉三角形的前4行:

   1

  1 1

 1 2 1

1 3 3 1

给出n,输出它的前n行。

输入描述:

输入包含一个数n。

输出描述:

输出杨辉三角形的前n行。每一行从这一行的第一个数开始依次输出,中间使用一个空格分隔。请不要在前面和后面输出多余的空格。

示例1

输入

4

输出

1
1 1
1 2 1
1 3 3 1

说明

1 <= n <= 34。

解答:

 1 #include<iostream>
 2 #define Maxn 100000
 3 using namespace std;
 4 
 5 int N;
 6 int a[Maxn];
 7 void Output(int n)
 8 {
 9     if(n==N+1)
10         return ;
11     a[n]=1;
12 //    for(int j=2;j<n;j++){
13 //        a[j]=a[j-1]+a[j];
14 //    }//与倒序循环有微妙差距 
15     for(int j=n-1;j>=2;j--){
16         a[j]=a[j-1]+a[j];
17     }
18     for(int j=1;j<=n;j++){
19         if(j==1){
20             cout<<a[j];
21         }else{
22             cout<<' '<<a[j];
23         }
24     }
25     cout<<endl;
26     Output(n+1);    
27 }
28 int main()
29 {
30     a[1]=1;
31     cin>>N;
32     Output(1);
33     return 0;
34 }

 

 

 

链接:https://ac.nowcoder.com/acm/problem/14356
来源:牛客网
 

★s01串

s01串初始为"0"
按以下方式变换
0变1,1变01

输入描述:

1个整数(0~19)

输出描述:

n次变换后s01串

示例1

输入

3

输出

101

说明

初始为0 第一次变化后为 1  第二次变化后为 01  第三次变化后为 101

备注:

数据规模和约定
0~19

解答:

 1 #include<iostream>
 2 using namespace std;
 3 
 4 string Output(int n)
 5 {
 6     if(n==0) return "0";
 7     if(n==1) return "1";
 8     return Output(n-2)+Output(n-1);
 9 }
10 int main()
11 {
12     int N;
13     cin>>N;
14     cout<<Output(N);
15     return 0;
16 }

 

 

2021/7/1

链接:https://ac.nowcoder.com/acm/problem/14703
来源:牛客网
 

★★素数回文

现在给出一个素数,这个素数满足两点:

1、  只由1-9组成,并且每个数只出现一次,如13,23,1289。

2、  位数从高到低为递减或递增,如2459,87631。

请你判断一下,这个素数的回文数是否为素数(13的回文数是131,127的回文数是12721)。

输入描述:

输入只有1行。

第1行输入一个整数t,保证t为素数。

数据保证:9<t<109

输出描述:

输出一行字符串,如果t的回文数仍是素数,则输出“prime”,否则输出"noprime"。

示例1

输入

13

输出

prime

说明

13的回文数是131,131是素数

示例2

输入

17

输出

noprime

说明

17的回文数是171,171不是素数(因子有3)

备注:

素数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数。
素数的回文数为题意中的定义,1331不是素数的回文数。

 

解答:

#include<iostream>
using namespace std;

bool Isprime(long long number)
{
    if(number<2) return false;
    for(int i=2; i<=number/i; i++)
    {
        if(number%i==0)
            return false;
    }
    return true;
}
int main()
{
    char num[10];    
    long long a,b,c;
    cin>>a;
    for(c=a/10; c!=0; c/=10)
    {
        a*=10;
        a+=c%10;
    }
    
    if(Isprime(a))
        cout<<"prime";
    else
        cout<<"noprime";
    
    return 0;
}

 

 

  链接:https://ac.nowcoder.com/acm/problem/14582
来源:牛客网

 


★★★LP钱不够

吃货LP参加了珠海美食节,每见一家摊位都会大吃一顿,但是如果不加收敛,接下来的日子就只能吃土了,所以,他决定只向前,不回头,花最少的钱,在美食节上吃出一条血路。在美食节的矩形地图中,LP站在左上角的入口,请帮助Ta到达右下角的出口。

输入描述:

第一行包含一个正整数T(T<=10),表示有T组测试数据。
每组数据第一行包含一个正整数n(3 <= n<=20)。
给定一个n*n矩阵图,从左上角开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是花费和,返回所有路径中最小的花费和。
无摊位时花费为0,不会有负花费。

输出描述:

对于每一组数据,有一行输出,返回最小花费,最后输出无换行。

示例1

输入

1
5
25 81 51 98 43 
19 10 36 81 91 
95 38 7 84 40 
87 27 72 9 30 
33 81 68 21 71

输出

270

 

解答:

 

#include<iostream>
using namespace std;

int main()
{
    int num[21][21]={0};
    int N,x;
    cin>>N;
    while(N--){
        cin>>x;
        for(int i=1; i<=x; i++)
        {
            for(int j=1; j<=x; j++)
                cin>>num[i][j];
        }
        
        for(int m=x;m>=1;){
            for(int n=x-1;m>=1;){
                for(int i=m,j=n;i>=m,j<=m;i--,j++){    
                        //cout<<"("<<i<<','<<j<<") "; 
                        if(i==x){
                            num[i][j]+=num[i][j+1];
                        }else if(j==x){
                            num[i][j]+=num[i+1][j];
                        }else{
                            num[i][j]+=min(num[i+1][j],num[i][j+1]);//保证每一个子问题的最优解
                        }    
                }
                //cout<<"("<<m<<','<<n<<") "; 
                if(n==1){
                    m--;
                }else{
                    n--;
                }
            }
        }
        cout<<num[1][1]<<endl;    
    }
    return 0;
}

 

 

这是一道数塔问题的变种,核心思想是相同的,即运用动态规划的思想,把一个复杂的问题划分成无数个子问题,保证每一个子问题的最优解,通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决.得到全局最优解

 

此题比起简单的数塔,难在DP的顺序,例如下图矩阵大小为4*4时:


 

 

 

 

而每一层的起始点循环的方向则是按照红线的顺序(不唯一)

 

 

补充:

数塔
在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:

有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?


已经告诉你了,这是个DP的题目,你能AC吗?
Input
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
Output
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
Sample Input
1
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
Sample Output
30

#include<iostream>
#include<cstdio>
using namespace std;

int N;
int a[10000],book[10000];

void dfs(int step)
{
    if(step==N+1)
    {
        for(int i=1; i<=N; i++)
        {
            printf("%5d",a[i]);
            //cout<<a[i]<<' ';
        } 
        cout<<endl;
        return ;
    }
    for(int i=1; i<=N; i++)
    {
        if(book[i]==0)
        {
            a[step]=i; 
            book[i]=1;
            dfs(step+1);
            book[i]=0;
        } 
    } 
    return ;
}
int main()
{    
    cin>>N;
    for(int i=1;i<=N;i++)
    {
        a[i]=i;
        book[i]=0;
    }
    dfs(1);

    return 0;
}

 

 

 

 

 

 

链接:https://ac.nowcoder.com/acm/problem/14839
来源:牛客网
 

 

★最大公约数

输入两个数,求最大公约数。

输入描述:

输入两个数a,b.

输出描述:

输出a和b的最大公约数

示例1

输入

6
3

输出

3

解答:

#include<iostream>
using namespace std;

int gcd(int a,int b){
    if(b==0) return a;
    return gcd(b,a%b); 
}
int main()
{
    int a,b;
    cin>>a>>b;
    cout<<gcd(a,b);
    return 0;
}

 

 

2021/7/2

链接:https://ac.nowcoder.com/acm/problem/14359
来源:牛客网
 

★Fibonacci数列

Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。

当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。

输入描述:

输入包含一个整数n。

输出描述:

输出一行,包含一个整数,表示Fn除以10007的余数。

示例1

输入

10

输出

55

示例2

输入

22

输出

7704

备注:


说明:在本题中,答案是要求Fn除以10007的余数,因此我们只要能算出这个余数即可,而不需要先计算出Fn的准确值,再将计算的结果除以10007取余数,直接计算余数往往比先算出原数再取余简单。

数据规模与约定

1 <= n <= 1,000,000。

解答:

#include<iostream>
using namespace std;

int main()
{
    int n;
    int num[3]={1,1,0};
    cin>>n;
    
    if(n==1||n==2){
        cout<<"1"; 
    }else{
        for(int i=3; i<=n; i++)
        {
            num[2]=(num[0]+num[1])%10007;
            num[0]=num[1];
            num[1]=num[2];
        }
        cout<<num[2];
    } 
    return 0;
}

 

 

 

 

 1.全排列

例题:洛谷P1706 全排列问题

题目描述

输出自然数 1 到 n 所有不重复的排列,即 nn 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

输入格式

一个整数 n。

输出格式

由 1∼n 组成的所有不重复的数字序列,每行一个序列。

每个数字保留 5 个场宽。

输入输出样例

输入

3

输出 

    1    2    3
    1    3    2
    2    1    3
    2    3    1
    3    1    2
    3    2    1

说明/提示

1≤n≤9

 

解答:

#include<iostream>
#include<cstdio>
using namespace std;

int N;
int a[10000],book[10000];

void dfs(int step)
{
    if(step==N+1)
    {
        for(int i=1; i<=N; i++)
        {
            printf("%5d",a[i]);
            //cout<<a[i]<<' ';
        } 
        cout<<endl;
        return ;
    }
    for(int i=1; i<=N; i++)
    {
        if(book[i]==0)
        {
            a[step]=i; 
            book[i]=1;
            dfs(step+1);
            book[i]=0;
        } 
    } 
    return ;
}
int main()
{    
    cin>>N;
    for(int i=1;i<=N;i++)
    {
        a[i]=i;
        book[i]=0;
    }
    dfs(1);

    return 0;
}

 

 

模板:

void dfs(int step)
{
    判断边界{
        ...// 输出
        返回 
    } 
    尝试每一种可能{
        判断状态{
            ...
            继续下一步 dfs(step+1) 
            ...//初始化执行这一步前所改变的状态
        }  
    } 
    返回 
}

 

2.所有组合

例题:洛谷P1157 组合的输出

 

题目描述

排列与组合是常用的数学方法,其中组合就是从n个元素中抽出rr个元素(不分顺序且r≤n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。

现要求你输出所有组合。

例如n=5,r=3,所有组合为:

12 3 , 1 2 4 , 1 2 5 , 1 3 4 ,1 3 5 , 1 4 5 , 2 3 4 , 2 3 5 , 2 4 5 , 3 4 5

输入格式

一行两个自然数n,r(1<n<21,0≤r≤n)。

输出格式

所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。

注意输出时,每个数字需3个场宽,pascal可以这样:

write(ans:3);

输入输出样例

输入 

5 3 

输出

  1  2  3
  1  2  4
  1  2  5
  1  3  4
  1  3  5
  1  4  5
  2  3  4
  2  3  5
  2  4  5
  3  4  5

 

解答:

#include<iostream>
#include<cstdio>
using namespace std;

int n,r;
int a[10000];

void dfs(int m)
{
    if(a[0]==r)
    {
        for(int i=1; i<=r; i++)
        {
            printf("%3d",a[i]);
            //cout<<a[i]<<' ';
        } 
        cout<<endl;
        return ;
    }
    for(int i=m; i<=n; i++)
    {
        a[++a[0]]=i;
        dfs(i+1);
        a[a[0]--]=0;
    } 
}
int main()
{    
    cin>>n>>r;
    dfs(1);
    return 0;
}

 

 



posted @ 2021-07-03 10:22  泥烟  阅读(118)  评论(0编辑  收藏  举报