蓝桥试题:摆花 389

一、题目描述

小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 m 盆。通过调查顾客的喜好,小明列出了顾客最喜欢的 n 种花,从 1 到 n 标号。为了在门口展出更多种花,规定第 i 种花不能超过 ai​ 盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。

试编程计算,一共有多少种不同的摆花方案。

输入描述

第一行包含两个正整数 n 和 m,中间用一个空格隔开。

第二行有 n 个整数,每两个整数之间用一个空格隔开,依次表示 a1、a2、......an。

其中,0<n≤100,0<m≤100,0≤ai≤100。

输出描述

输出只有一行,一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案1e6+7取模的结果。

输入输出样例

示例

输入

2 4
3 2

输出 

2

二、代码展示 

import java.util.Scanner;

public class Main {
public static void main(String[] args) {
    Scanner scan=new Scanner(System.in);
    int n=scan.nextInt();
    int m=scan.nextInt();
    int[][] dp=new int[n+1][m+1];//n为花的种类,m为总共盆数
    int[] a=new int[n+1];//用来表示每种花摆多少盆
    for(int i=1;i<=n;i++) {
        a[i]=scan.nextInt();
    }
    for(int i=0;i<=n;i++) {//表示第i种花摆0盆为1种方案
        dp[i][0]=1;
    }
    for(int i=1;i<=n;i++) {//遍历花的种类
        for(int j=1;j<=m;j++) {//遍历花的总盆数
            for(int k=0;k<=j&&k<=a[i];k++) {
                dp[i][j]+=dp[i-1][j-k];//表示第i种花摆j盆的方案数
                dp[i][j]%=(int)1e6+7;
            }
        }
    }
    System.out.println(dp[n][m]);
}
}

逐行解释

1. 外层循环:遍历花的种类
for (int i = 1; i <= n; i++) {
  • 作用:遍历每一种花,从第 1 种到第 n 种。

  • 意义:动态规划的阶段,逐步考虑前 i 种花的摆放方案。


2. 中层循环:遍历花的总盆数
for (int j = 1; j <= m; j++) {
  • 作用:遍历需要摆放的花的总盆数,从 1 盆到 m 盆。

  • 意义:动态规划的状态,计算前 i 种花摆 j 盆的方案数。


3. 内层循环:遍历第 i 种花摆 k 盆
for (int k = 0; k <= j && k <= a[i]; k++) {
  • 作用:遍历第 i 种花可以摆放的盆数 kk 的取值范围是:

    • 0 到 j(不能超过总盆数 j)。

    • 0 到 a[i](不能超过第 i 种花的最大盆数)。

  • 意义:枚举第 i 种花摆放的盆数 k,并累加前 i-1 种花摆 j-k 盆的方案数。


4. 状态转移
dp[i][j] += dp[i - 1][j - k];
  • 作用:更新 dp[i][j],表示前 i 种花摆 j 盆的方案数。

  • 意义

    • dp[i][j] 是前 i 种花摆 j 盆的方案数。

    • dp[i - 1][j - k] 是前 i-1 种花摆 j - k 盆的方案数。

    • 通过累加所有可能的 k,得到前 i 种花摆 j 盆的总方案数。


5. 取模防止溢出
dp[i][j] %= (int) 1e6 + 7;
  • 作用:对 dp[i][j] 取模,防止数值过大导致溢出。

  • 意义

    • 1e6 + 7 是题目要求的模数(即 1000007)。

    • 每次更新 dp[i][j] 后,取模确保结果在合理范围内。


动态规划的状态转移方程

  • 设 dp[i][j] 表示前 i 种花摆 j 盆的方案数。

  • 状态转移方程:

    𝑑𝑝[𝑖][𝑗]=∑𝑘=0min⁡(𝑗,𝑎[𝑖])𝑑𝑝[𝑖−1][𝑗−𝑘]dp[i][j]=k=0∑min(j,a[i])​dp[i−1][j−k]
    • 其中,k 表示第 i 种花摆 k 盆。

    • dp[i-1][j-k] 表示前 i-1 种花摆 j-k 盆的方案数。


示例说明

假设:

  • n = 2(2 种花)。

  • m = 4(总共摆 4 盆花)。

  • a[1] = 3(第 1 种花最多摆 3 盆)。

  • a[2] = 2(第 2 种花最多摆 2 盆)。

DP 表填充过程

  1. 初始化

    • dp[0][0] = 1

    • 其他 dp[i][0] = 1

  2. 填充 i = 1(第 1 种花)

    • j = 1

      • k = 0dp[1][1] += dp[0][1] = 0

      • k = 1dp[1][1] += dp[0][0] = 1

      • 结果:dp[1][1] = 1

    • j = 2

      • k = 0dp[1][2] += dp[0][2] = 0

      • k = 1dp[1][2] += dp[0][1] = 0

      • k = 2dp[1][2] += dp[0][0] = 1

      • 结果:dp[1][2] = 1

    • 类似地,dp[1][3] = 1dp[1][4] = 0

  3. 填充 i = 2(第 2 种花)

    • j = 1

      • k = 0dp[2][1] += dp[1][1] = 1

      • k = 1dp[2][1] += dp[1][0] = 1

      • 结果:dp[2][1] = 2

    • j = 2

      • k = 0dp[2][2] += dp[1][2] = 1

      • k = 1dp[2][2] += dp[1][1] = 1

      • k = 2dp[2][2] += dp[1][0] = 1

      • 结果:dp[2][2] = 3

    • 类似地,dp[2][3] = 3dp[2][4] = 2

最终结果

  • dp[2][4] = 2,即共有 2 种摆花方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值