• YbtOJ「基础算法」第1章 递推算法


    YbtOJ 大全

    【例题1】错排问题

    f [ n ] f[n] f[n] 表示 n n n 个数时的合法方案数。初始化 f [ 1 ] = 0 , f [ 2 ] = 1 f[1]=0,f[2] = 1 f[1]=0,f[2]=1。当 n ≥ 3 n \geq 3 n3 时,我们考虑一个位置 k k k,把 n n n 放在位置 k k k ( k ≠ n ) (k \ne n) (k=n),共有 n − 1 n-1 n1 种方法。接下来分两类讨论。

    1. 1. 1. 如果 k k k 放在了位置 n n n 上,相当于 k k k n n n 自己颠倒,和剩下的 n − 2 n-2 n2 的数无关,此时的合法方案数是 f [ n − 2 ] f[n-2] f[n2]

    2. 2. 2. 如果 k k k 没有放在位置 n n n 上,相当于 n n n 这个数放的位置是合法的,把 k k k 看成 n n n,位置 n n n 看成 k k k 对应的位置 k 1 k1 k1 k k k 没有放在 k 1 k1 k1 这个位置,就相当于是 n − 1 n-1 n1 个数的子问题,此时合法的方案数是 f [ n − 1 ] f[n-1] f[n1]

    所以递推式 f [ n ] = ( n − 1 ) × ( f [ n − 1 ] + f [ n − 2 ] ) f[n] = (n-1) \times (f[n-1] + f[n-2]) f[n]=(n1)×(f[n1]+f[n2]) ( n ≥ 3 ) (n \geq 3) (n3)

    #include 
    #include 
    #include 
    #include 
    #include 
    #define re register
    #define int long long
    #define rep(a,b,c)  for(re int a(b) ; a<=c ; ++a)
    #define drep(a,b,c) for(re int a(b) ; a>=c ; --a)
    using namespace std;
    inline int read(){
       
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
       if(ch == '-') f=-1 ; ch=getchar();}
        while(ch>='0'&&ch<='9'){
       x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
        return x*f;
    }
    const int M = 100;
    int n;
    int f[M];
    signed main(){
       
        n = read();
        f[1] = 0,f[2] = 1;
        rep(i,3,n) f[i] = (i-1)*(f[i-1]+f[i-2]);
        printf("%lld\n",f[n]);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    【例题2】传球游戏

    f [ i ] [ j ] f[i][j] f[i][j] 表示球在第 i i i 个人手中,传了 j j j 次的方案数,初值 f [ 1 ] [ 0 ] = 1 f[1][0] = 1 f[1][0]=1

    1. 1. 1. i = 1 i = 1 i=1 时, i i i n n n 2 2 2 相邻, f [ i ] [ j ] = f [ n ] [ j − 1 ] + f [ 2 ] [ j − 1 ] f[i][j] = f[n][j-1] + f[2][j-1] f[i][j]=f[n][j1]+f[2][j1]

    2. 2. 2. i = n i = n i=n 时, n n n n − 1 n-1 n1 1 1 1 相邻, f [ i ] [ j ] = f [ 1 ] [ j − 1 ] + f [ n − 1 ] [ j − 1 ] f[i][j] = f[1][j-1] + f[n-1][j-1] f[i][j]=f[1][j1]+f[n1][j1]

    3. 3. 3. 其余情况, f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + f [ i + 1 ] [ j − 1 ] f[i][j] = f[i-1][j-1] + f[i+1][j-1] f[i][j]=f[i1][j1]+f[i+1][j1]

    注意要先循环 j j j,因为 f [ i ] [ j ] f[i][j] f[i][j] 对于 j j j 的转移只和 j − 1 j-1 j1 有关,而对于 i i i 的转移不仅仅只有一种情况。最后的答案就是 f [ 1 ] [ m ] f[1][m] f[1][m],要传回第一个人手中。

    #include 
    #include 
    #include 
    #include 
    #include 
    #define re register
    #define int long long
    #define rep(a,b,c)  for(re int a(b) ; a<=c ; ++a)
    #define drep(a,b,c) for(re int a(b) ; a>=c ; --a)
    using namespace std;
    inline int read(){
       
        int x=0,f=1;
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    Unity的粒子总是丢材质
    Linux进程基本知识详解
    git 合并两个不同仓库
    MQ - 37 云原生:MQ的分层存储架构的实现方案
    vite2.x+vue3.x项目配置
    非对称加密(RSA)详解
    dpdk 运行testpmd 出现: Couldn‘t get fd on hugepage file (已解决)
    高效查找对标账视频号
    安装rsa依赖库出现ERROR: No matching distribution found for rsa
    Python练习题:从列表中选取任意个元素求和
  • 原文地址:https://blog.csdn.net/glorious_dream/article/details/126449986