递归练习题

思考1.在不考虑n!溢出的情况下,编程实现阶乘问题

C++实现

比较简单,不多赘述,通过循环实现

ll fac(int n){
    ll res=1;
    for(int i=1;i<=n;i++)res*=i;
    return res;
}

子问题:求(n-1)! 子问题合并 :n*(n-1)!

ll fac(int n){
    if(n==0)return 1;
    else return fac(n-1)*n;
}

python

from math import *
print(factorial(6))

习题1

题目:猴子吃桃,猴子每天吃一半多一个,第10天只剩1个,问第一天剩多少个

从最后一天开始递归,要是d=1,表示第一天,直接输出rest; 不然逆推上一天,x=x-1,rest=(rest+1)*2

C++实现

#include<bits/stdc++.h>
using namespace std;
int f(int d,int rest){
    return ( d==1 ? rest : f(d-1,(rest+1)*2));
}
int main(){
    cout<<f(10,1);
    return 0;
}

python

def f(d,rest):
    if d==1 :
        return rest
    else :
        return f(d-1,(rest+1)*2)
print(f(10,1))

习题二

题目:三齿轮问题。三个齿轮,齿数分别为a,b,c,问各自转多少圈后,这两对齿重逢

说实话没咋看懂题目,但根据题目样例应该是输出lcm(本身gcd就递归实现的)

C++

#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b){
    return !b ? a : gcd(b,a%b);
}
int main(){
    int a,b,c;cin>>a>>b>>c;
    cout<<b*c/gcd(b,c)<<' ';
    cout<<a*c/gcd(a,c)<<' ';
    cout<<b*a/gcd(b,a)<<' ';
    // C++自带gcd: __gcd()
    return 0;
}

python

python math中带有lcm,gcd

from math import *
a,b,c=3,4,5
print(lcm(c,b),lcm(c,a),lcm(a,b))

习题三

题目:输入一个n(n\leqslant2000000000)求它的分解式总数(Eg.12 ---- 8)

此题如果规模扩大,应该要用pollard rho,这里直接分解 可以得到递归公式f(x)=1+\sum_{t_i}^{t_i为<x的因子}f(\frac{x}{p_i}) 对于每个质数 f(x)=1

C++

下面用了 miller_rabin判断素数,因为有模板,直接贴了 或者存个质数的表,二分查找判素也行

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll cnt=0,fac[10010];
ll qpow(ll x,ll n,ll p) {
    ll res=1;
    while(n){
        if(n&1)res=res*x%p;
        x=x*x%p;
        n>>=1;
    }
    return res;
}
bool query(ll p) {
    int test[10]={2,3,5,7,11,13,17};
    if(p==1)return 0;
    ll t=p-1,k=0;
    while(!(t&1))k++,t>>=1;
    for(int i=0;i<4;i++){
        if(p==test[i])return 1;
        ll a=qpow(test[i],t,p),nxt=a;
        for(int j=1;j<=k;j++){
            nxt=(a*a)%p;
            if(nxt==1 && a!=1 && a!=p-1) return 0;
            a=nxt;
        }
        if(a!=1) return 0;
    }
    return 1;
}
ll f(ll x){
    if(query(x) || x==1)return 1;
    else {
        ll res=0;
        for(int i=0;i<cnt && fac[i]<x;i++){
            if(x%fac[i]==0)res+=f(x/fac[i]);
        }
        res+=1;
        return res;
    }
}
int main(){
    ll x;cin>>x;
    for(int i=2;i*2<=x;i++){
        if(x%i==0)fac[cnt++]=i;
    }
    cout<<f(x);
    return 0;
}

python

from Crypto.Util.number import *
def f(x):
    if isPrime(x) | x==1 :
        return 1
    else :
        res=0;
        for i in range(len(fac)):
            if fac[i]>=x :
                break
            if x%fac[i]==0 :
                res+=f(x//fac[i])
        res+=1;
        return res;
​
fac=[]
x=12
for i in range(2,x//2+1) :
    if x%i==0 :
        fac.append(i)
print(f(x))

习题四

题目:有重复元素的排列问题,输出有重复元素集合的排列

next_permutation yyds bool next_permutation(iterator start,iterator end) next_permutation会把调整序列改为下一个字典序

C++

#include<bits/stdc++.h>
using namespace std;
int main(){
    string s("abcb");
    sort(s.begin(),s.end());
    do{
        for(int i=0;i<s.size();i++)cout<<s[i]<<' ';
        cout<<endl;
    }while(next_permutation(s.begin(),s.end()));
    return 0;
}

习题五

题目:求一个集合的全部子集

运用二进制数模拟子集的每个位置上的数是否取出

C++

#include<bits/stdc++.h>
using namespace std;
int a[]={1,5,6,9};
int main(){
    for(int i=0;i<16;i++){
        int tem=i;
        for(int j=0;j<4;j++){
            if(j&1)cout<<a[j]<<' ';
        }
        cout<<endl;
    }
    return 0;
}

习题六

题目:求n个数中r个数的全部组合问题

#include<bits/stdc++.h>
using namespace std;
int n,r;
bool b[20];
void print(){
    for(int i=1;i<=n;i++)
        if(b[i])cout<<i<<' ';
    cout<<endl;
}
void dfs(int k,int p){//k表示已经标记的个数 p表示搜索到的位置
    if(k==r) print();
    else if(p>n)return;//到最后位置后的一个位置
    else {
        b[p]=true;
        dfs(k+1,p+1);
        b[p]=false;
        dfs(k,p+1);
    }
}
int main(){
    cin>>n>>r;
    dfs(0,1);
    return 0;
}

习题八

题目:某人上楼梯一次可以上1,2,3格,输出所有可能,总共n阶台阶

简单递归,从最后一个台阶往前,a记录每次走了几阶,step表示走了几步,rest表示还剩下几阶要走

C++

#include<bits/stdc++.h>
using namespace std;
int a[6];
void f(int step,int rest){
    if(rest==0){
        for(int i=0;i<step;i++)
            cout<<a[i]<<' ';
        cout<<endl;
    }
    else{
        for(int i=1;i<=3 && i<=rest;i++){
            a[step]=i;
            f(step+1,rest-i);
        }
    }
}
int main(){
    int n=5;
    f(0,5);
    return 0;
}

python

类似C++

a=[0]*6;
def f(step,rest) :
    if rest==0 :
        for i in range(1,step+1):
            print(a[i],end=' ')
        print()
    else :
        for i in range(1,4):
            if i>rest :
                break
            a[step+1]=i
            f(step+1,rest-i)
​
f(0,5)

习题九

题目:集合划分问题,将n个元素的集合划分为m个

这道题跟6思路基本相同,先用6的方法得到m-1个划分的位置的所有可能,然后按照划分位置分别输出即可

题解略


习题十

题目:n皇后问题(n*n棋盘),输出所有摆放方案

$$
\begin{matrix}

0 & * & 0 \\

* & 0 & 0 \\

0 & 0 & *

\end{matrix} \tag{1}
$$

写了好多次了 懒得写了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值