动态规划例题(有趣的数字 + 放苹果)

参考:

https://www.bilibili.com/video/BV1DX4y157r2

 

 

一,有趣的数字

1,链接:http://118.190.20.162/view.page?gpid=T2

 

2,dp 求解

函数关系:

  对于第 i 位的状态,根据它前面所出现的数字,总共可列出有 6 种状态。而对于第 i 位的状态的情况就可以根据 第 i-1 位的状态推出。

    ① 第 i 位及其之前所有位 只存在 2

    ② 第 i 位及其之前所有位 只存在 2 0

    ③ 第 i 位及其之前所有位 只存在 2 3

    ④ 第 i 位及其之前所有位 只存在 2 0 1

    ⑤ 第 i 位及其之前所有位 只存在 2 3 0

    ⑥ 第 i 位及其之前所有位 只存在 2 3 0 1

    若 第 i 位 为 ① 状态,则只能是 i-1 位 的 ① 状态 +2,这一种情况

    若 第 i 位 为 ② 状态,可能是 i-1 位 的 ① 状态 +0 或  i-1 位 的 ②状态 +0  或 i-1 位 的 ②状态 +2 ,这三种情况

    若 第 i 位 为 ③ 状态,可能是 i-1 位 的 ① 状态 +3 或  i-1 位 的 ③状态 +3,这两种情况

    若 第 i 位 为 ④ 状态,可能是 i-1 位 的 ② 状态 +1 或  i-1 位 的 ④状态 +1  或 i-1 位 的 ②状态 +2,这三种情况

    若 第 i 位 为 ⑤ 状态,可能是 i-1 位 的 ② 状态 +3 或  i-1 位 的 ③状态 +0  或 i-1 位 的 ⑤状态 +0 或  i-1 位 的 ⑤状态 +3,这四种情况

    若 第 i 位 为 ⑥ 状态,可能是 i-1 位 的 ④ 状态 +3 或  i-1 位 的 ⑤状态 +1  或 i-1 位 的 ⑥状态 +0 或  i-1 位 的 ⑤状态 +3,这四种情况

    于是,我们就得到第 i 位包含 2 3 0 1 这四种数字的所有可能。

函数出口:

  最高位只能为 2 ,最高位只存在 ①状态,所以当 i 为 1 时 ① 状态只有一种情况 ,其他状态 为 0

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define N 1002
#define MOD 1000000007
#define ll long long
ll dp[N][7];   // 6种状态
ll fun(ll n, ll m)   // n 为位数,m 为第几种状态
{
    if (m == 1)
        return 1;
    if (n == 1)
        return 0;
    if (m == 2)
        return (fun(n - 1, 1) + fun(n - 1, 2) * 2) % MOD;
    if (m == 3)
        return (fun(n - 1, 1) + fun(n - 1, 3)) % MOD;
    if (m == 4)
        return (fun(n - 1, 2) + fun(n - 1, 4) * 2) % MOD;
    if (m == 5)
        return (fun(n - 1, 2) + fun(n - 1, 3) + fun(n - 1, 5) * 2) % MOD;
    if (m == 6)
        return (fun(n - 1, 4) + fun(n - 1, 5) + fun(n - 1, 6) * 2) % MOD;
}
void fun2(int n)
{
    for (int i = 1; i <= n; i++) 
    {
        dp[i][1] = 1 % MOD;
        dp[i][2] = (dp[i - 1][1] + dp[i - 1][2] * 2) % MOD;
        dp[i][3] = (dp[i - 1][1] + dp[i - 1][3]) % MOD;
        dp[i][4] = (dp[i - 1][2] + dp[i - 1][4] * 2) % MOD;
        dp[i][5] = (dp[i - 1][2] + dp[i - 1][3] + dp[i - 1][5] * 2) % MOD;
        dp[i][6] = (dp[i - 1][4] + dp[i - 1][5] + dp[i - 1][6] * 2) % MOD;
    }
}
int main(void)
{
    int n; scanf("%d", &n);
    
    // printf("%lld\n", fun(n, 6));  // 超时
    fun2(n);
    printf("%lld\n", dp[n][6]);

    system("pause");
    return 0;
}
View Code

 

3,组合计数

  设 0 1 的总个数为 k,则 2 3 的总个数为 n-k。

  ① n 个数中,k 个 0 1 的选法

    且由于 0 不能放在首位,而 1 要在 0 之后,所以 1 也不能放在首位。那么对于 n 个数,其中共有 n-1 个数可供 k 个 0 1 存放,即 c( n-1, k)

  ② k 个 0 1 中,0 1 不同的选择

    设 0 的个数为 t,则 1 <= t <= k-1

    由于 0 总在 1 之前,所以 0 总是连续的排在 1 前面,即对于每个 t,0 1 只有 1 中选法。

    而 t 共有 k-1 种可能,所以总共有 k-1 种选择。

  ③  n - k 个 2 3 中,2 3 不同的选择

    设 2 的个数为 t,则 1 <= t <= n -k-1

    由于 2 总在 3 之前,所以 2 总是连续的排在 3 前面,即对于每个 t,2 3 只有 1 中选法。

    而 t 共有 n-k-1 种可能,所以总共有 n-k-1 种选择。

  综上,总共的选法为上述可能相乘。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define N 1002
#define MOD 1000000007
#define ll long long
ll c[N][N];
int main(void)
{
    int n; scanf("%d", &n);
    
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= i; j++)
            if (j == 0)
                c[i][j] = 1;
            else
                c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % MOD;
    int rs = 0;
    for (int i = 2; i <= n; i++)
        rs = (rs + c[n - 1][i] * (i - 1)*(n - i - 1)) % MOD;
    printf("%lld\n", rs);

    system("pause");
    return 0;
}
View Code

 

 

 

二,放苹果:

1,问题:

  把 M 个同样的苹果放在 N 个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K 表示)5,1,1 和 1,5,1 是同一种分法。

 2,推导

   ① 函数关系式 f(n, m)

    当 m > n 时,f(n, m) = f(n, n)

    当 n >= m 时

      有篮子为空时,则至少一个篮子为空

        f(n, m-1)

      无篮子为空时,则一个篮子拿掉一个苹果

        f(n-m, m)

  ② 递归结束条件

    无苹果时  0

    无篮子时  1

    其中,不存在既无苹果,又无篮子的情况。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int fun(int n, int m)  // 苹果数  盘子数
{
    if (n == 0)   // 没有苹果
        return 1;
    if (m == 0)   // 没有盘子
        return  0;
    if (m > n)    //  盘子比苹果多 (一定有篮子为空)
        return fun(n, n);
    else          //  分两种,有无篮子为空  
        return fun(n, m - 1) + fun(n - m, m);
}
int main(void)
{
    int a[15][15] = { 0 };
    for (int i = 1; i < 15; i++)
    {
        a[0][i] = 1;   // 0个苹果
        a[i][0] = 0;   // 0个篮子
    }
    for (int n = 1; n < 15; n++)
    {
        for (int m = 1; m < 15; m++)
        {
            if (m > n)
                a[n][m] = a[n][n];
            else
                a[n][m] = a[n][m - 1] + a[n - m][m];
        }
    }

    int M, N, k;
    printf("请输入有几个苹果并回车:");
    scanf("%d", &M);
    printf("请输入有几个篮子并回车:");
    scanf("%d", &N);

    //k = a[M][N];           //动态规划
    k = fun(M, N);       // 递归
    printf("%d\n", k);

    system("pause");
    return 0;
}
View Code

 

 

 

=========== ======== ======== ======= ===== ===== ==== === == =

  面对强大的对手,明知不敌,也要毅然亮剑,即使倒下,也要化成一座山,一道岭。

   

posted @ 2020-03-11 10:27  叫我妖道  阅读(262)  评论(0编辑  收藏  举报
~~加载中~~