洛谷P1077摆花

一、题目描述

https://www.luogu.com.cn/problem/P1077
题目描述很容易看懂

二、思路

动态规划题目,首先定义状态
dp[i][j]:摆前i种花,一共摆j盆的方案数。
i:1~n
j:1~m
需要注意的时,第i种花摆放的盆数范围是0~a[i].所以我们需要枚举 第
i种花 摆放多少盆。所以来一个三重循环。
状态转移方程:
k:1~a[i]&&k<m。dp[i][j]+=dp[i][j]+dp[i-1][j-k]
即在i,j确定的情况下,我们是需要枚举k,k为每次第i盆花放了k盆。
状态转移:第i盆花放了k盆,那么前i-1盆花就放了 j-k盆!

初始化:初始化个人感觉不是很容易,博主在这摔了跟头。因为我第一次的为dp[1][1]=1;一想感觉没什么问题。
但是dp[1][1]不一定等于1! 如果a[1]=0 的话 dp[1][1]就等于0了!!
所以初始化为 dp[0][0]=1 。从第一行i=1 而不再是i=2开始。

还要注意 取模1000007


滚动数组:
来一手滚动数组 将二维变一维。也就是覆盖 将这一行的值覆盖上一行。
对于滚动数组,我们就要思考 是正推还是逆推
状态转移时,对于每一行,我们都需要上一行前面的值,所以我们要逆推!
防止前面的值先被覆盖。
初始化 仍然dp[0]=1;
但是注意这里 k 一定要从1开始。
因为我们初始化时dp[0]=1的含义已经包含了 第i种花 一个也没选的情况

三、代码

#include <iostream>
#include <cstdio>
using namespace std;

int main(){
    int n,m,a[105],dp[105][105]={0};
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    //初始化
    dp[0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m;j++){
            for(int k=0;k<=a[i]&&k<=j;k++){
                dp[i][j]=(dp[i][j]+dp[i-1][j-k])%1000007;
            }
        }
    }
    printf("%d",dp[n][m]);
    return 0;
}

滚动数组:

#include <iostream>
#include <cstdio>
using namespace std;

int main(){
    int n,m,a[105],dp[105]={0};
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    dp[0]=1;
    for(int i=1;i<=n;i++){
            //一定要逆推
        for(int j=m;j>=0;j--){
            for(int k=1;k<=a[i]&&k<=j;k++){
                dp[j]=(dp[j]+dp[j-k])%1000007;
            }
        }
    }
    printf("%d",dp[m]);
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mae_strive

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值