过程函数与递归
★题目一: 计算满足数(巧用递推)
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 个整数
以及 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;
}