C++程序设计基础:过程函数与递归

★题目一: 计算满足数(巧用递推)

1. 题目说明

1.1 题目描述

我们要求找出具有下列性质数的个数(包含输入的自然数nn):
先输入一个自然数nn(n \le 1000n≤1000),然后对此自然数按照如下方法进行处理:
1、不作任何处理;
2、在它的左边加上一个自然数,但该自然数不能超过原数的一半;
3、加上数后,继续按此规则进行处理,直到不能再加自然数为止.

1.2 输入输出

输入格式
1个自然数n (n≤1000)
输出格式
1个整数,表示具有该性质数的个数。
输入输出样例

输入 #1
6

输出 #1
6

1.3 说明/提示

以上结果结果的6个数分别为:
6,16,26,126,36,136

2. 代码与解答

2.1 注意点

1、在数学推到过程中,不必求出每个数是几,甚至每次添加在数的左侧还是右侧都无所谓。不过需要考虑最后非零
2、数学递推:

f[1]=1
f[2]=2=f[1]+1
f[3]=2=f[1]+1
f[4]=4=f[1]+f[2]+1
f[5]=4=f[1]+f[2]+1

2.2 题解

#include<bits/stdc++.h>//万能头文件
using namespace std;
int main()
{
    int n;
	int f[1005]={};//存每一位数的种类
	cin>>n;
    for(int i=1;i<=n;i++)//1-n的递推
	{ 
        for(int j=1;j<=i/2;j++)
		{
            f[i] = f[i] + f[j]; //每一位叠加,递推走起
        }
        f[i]++; //加上本身
    }
    cout<<f[n];//输出n的种类
    return 0;
}

★题目二:选数(递归与回溯/质数)

1. 题目说明

1.1 题目描述

已知 nn 个整数 x 1 , x 2 , x n x_1,x_2,…x_n 以及 1个整数k(k<n)。从n个整数中任选k个整数相加,可分别得到一系列的和。例如当n=4,k=3,4个整数分别为3,7,12,19时,可得全部的组合与它们的和为:
3+7+12=22
3+7+19=29
7+12+19=38
3+12+19=34
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:3+7+19=29。

1.2 输入输出

输入格式
键盘输入,格式为:
n,k(1≤n≤20,k<n)
且(1≤xi≤5000000)
输出格式
屏幕输出,格式为: 1个整数(满足条件的种数)。
输入输出样例

输入 #1
4 3
3 7 12 19

输出 #1
1

2. 代码与解答

2.1注意点

巧用递归,注意回溯!

2.2解答代码

#include<bits/stdc++.h>
using namespace std;

int n,k,num = 0;
int a[25];
long long ans=0;
bool isprime(int a)//判断质数 
{
	if(a==2) return true;//特判2 
    for(int i=2;i*i<=a;i++)
        if(a%i==0)//如果整除,即非质数 
            return false;
    return true; //是质数true
}

void dfs(int x,int y)//定义深搜的函数,y是当前最后选过的数在数组中的位置,x是当前正在选择第几个数,和用num变量储存
{
    int i,j;//for循环使用,不解释
    if(x>k){//如果选的数已经比k多了,就检测总和num是否为质数
        if(isprime(num)) ans++; //是就增加ans
        return ;
    }
    for(i=y+1;i<=n;i++)//否则继续搜索下一个数
    {
        num+=a[i];//取数
        dfs(x+1,i);//搜索
        num-=a[i];//回溯
    }
}
int main(){
	cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    dfs(1,0);
    cout<<ans;
    return 0;
}

★题目三:火柴棒等式(暴力数学转化)

1. 题目说明

1.1 题目描述

给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。用火柴棍拼数字0-9的拼法如图所示:
在这里插入图片描述

1.2 输入输出

输入格式
一个整数n(n<=24)。
输出格式
一个整数,能拼成的不同等式的数目。
输入输出样例

输入 #1
14

输出 #1
2

输入 #2
18

输出 #2
9

1.3 说明

【输入输出样例1解释】
2个等式为 0+1=1 和 1+0=1。
【输入输出样例2解释】
9个等式为:

0+4=4
0+11=11
1+10=11
2+2=4
2+7=9
4+0=4
7+2=9
10+1=11
11+0=11

2. 代码与解答

2.1注意点

把每个数字需要的火柴数全部算出来
1、注意定义初数组时,数字0需要6个,其他数字全初始化为0
2、注意最后还要加运算符号的个数:4

2.2解答代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a[2001]={6};//只定义第一个数为6,其他全为0 
	int n,c[10]={6,2,5,5,4,5,6,3,7,6},ans=0;
    cin>>n;
    for(int i=1;i<=2000;i++)
    {
        int j=i;
        while(j>=1)//求每个数所用的火柴棒
        {
            a[i]=a[i]+c[j%10];
            j=j/10;
        }
    }
    for(int i=0;i<=1000;i++)
    {
        for(int j=0;j<=1000;j++)
        {
        	if(a[i]+a[j]+a[i+j]+4==n) ans++;//还有加号与等号
        }
    }
    cout<<ans;
    return 0;
}

★题目四:回文质数 Prime Palindromes(同时满足回文数与质数)

1. 题目说明

1.1 题目描述

因为 151 既是一个质数又是一个回文数(从左到右和从右到左是看一样的),所以 151 是回文质数。
写一个程序来找出范围 [a,b]
(5≤a<b≤100,000,000)( 一亿)间的所有回文质数。

1.2 输入输出

输入格式
第 1 行: 二个整数 a 和 b .
输出格式
输出一个回文质数的列表,一行一个。
输入输出样例

输入 #1
5 500

输出 #1
5
7
11
101
131
151
181
191
313
353
373
383

1.3 说明与提示

Hint 1: Generate the palindromes and see if they are prime.
提示 1: 找出所有的回文数再判断它们是不是质数(素数).
Hint 2: Generate palindromes by combining digits properly. You might need more than one of the loops like below.
提示 2: 要产生正确的回文数,你可能需要几个像下面这样的循环。

产生长度为5的回文数:

for (d1 = 1; d1 <= 9; d1+=2) {    // 只有奇数才会是素数
     for (d2 = 0; d2 <= 9; d2++) {
         for (d3 = 0; d3 <= 9; d3++) {
           palindrome = 10000*d1 + 1000*d2 +100*d3 + 10*d2 + d1;//(处理回文数...)
         }
     }
 }

2. 代码与解答

本题不可直接嵌套循环+递归,会RE

2.1解答代码

#include<bits/stdc++.h>
using namespace std;
bool isprime(int x){ //判断质数的函数,应该不用我多解释
    if(x<2)return false;
    if(x==2)return true;
    for(int i=2;i*i<=x;i++){
        if(x%i==0)return false;
    }
    return true;
}
int l,r,x,y; //l,r是题目范围,x,y是他们的长度
int a[10];  //储存创造出来的数
bool b=true;  //用来作为是否跳出的判断
void go(int x,int k){  //k是总位数,x是目前枚举到的位置
    if(x==(k+1)/2){  //(k+1)/2是k位的中间数,可以自己算一下
        for(int i=k;i>x;i--){  //把剩下的位数完善
            a[i]=a[k-i+1];
        }
        int shu=0;  //将数组转化成数
        for(int i=1;i<=k;i++){
            shu=shu*10+a[i];
        }
        if(shu<l)return; //小于l就跳过
        if(shu>r){ //大于r就跳出
            b=false;
            return;
        }
        if(isprime(shu))cout<<shu<<endl; //是质数就输出
        return; //这个一定不能漏,要不然会一直搜下去(本人是亲身体验过的受害者)
    }
    int i;
    if(x)i=0;
    else i=1; //最高位不能是0
    for(i=i;i<=9;i++){ //dfs(深度优先搜索)下一位,没学过可以去看下P1706
        if(b==false)return; //如果已经出现大于r的数,就跳出函数
        a[x+1]=i;
        go(x+1,k);
    }
    return;
}
int weishu(int j){ //计算一个数的长度
    int b=j,count=0;
    while(b>0){
        b/=10;
        count++;
    }
    return count;
}
int main(){
    cin>>l>>r;
    x=weishu(l);
    y=weishu(r);
    for(int i=x;i<=y;i++){
        if(i==1){ //一位数特判
            if(l<=5&&r>=5)cout<<5<<endl;
            if(l<=7&&r>=7)cout<<7<<endl;
            continue;
        }
        if(i==2){ //两位数特判
            if(l<=11&&r>=11)cout<<11<<endl;
            continue;
        }
        if(i%2==0)continue; //偶数位就跳过
        if(i==9)break; //九位直接跳出
        b=true; //每次搜索要先重置这个变量
        go(0,i); //从第0位开始搜
    }
    return 0;
}
发布了27 篇原创文章 · 获赞 6 · 访问量 535

猜你喜欢

转载自blog.csdn.net/qq_43246110/article/details/104211534