上题:
题目描述
小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆。通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号。为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。
试编程计算,一共有多少种不同的摆花方案。
输入
第一行包含两个正整数n和m,中间用一个空格隔开。
第二行有n个整数,每两个整数之间用一个空格隔开,依次表示a1、a2、……an。
输出
输出只有一行,一个整数,表示有多少种方案。
样例输入
2 4
3 2
样例输出
2
本题看到之后就会自然联想到dp
因为前面的花的摆放会影响到后面的花摆放方式
故通过理解
发现了这个状态转移方程
dp[i][j] = dp[i-1][j-0] + dp[i-1][j-1] + dp[i-1][j-2] + ...... + dp[i-1][j-min(a[i], j)]
对于这于方程是这样理解的
前i个位置的花的摆放(包括第i个位置)是由前i-1个位置花的摆放决定的,前i-1个位置的花数量确定了,那么最后一个位置的花的数量也相继确定,所以通过这些循环累加即确定了前i个位置的所以摆放方案。
我们面临这样一个问题,就是上式中的红体部分如何得到的
因为题目中有要求,第i个位置的摆花数量不得超过a[i]个,而前i个位置的数量又不得超过j个
红题部分即第i个位置摆0个,摆1个,摆2个,......摆min(a[i], j)个
摆min(a[i], j)是因为第i个位置最多摆a[i]个,而总共前i个位置只能摆j个,所以第i个位置的最多数量是两者中的较小值。
这里你可能会疑惑如果前i-1个位置的a[1]+...a[i-1] < j改如何,这时候的话这种情况就是不存在的,故我们只需要在状态转移前将其全部初始化为0即可
但是尽量不要用memset初始化二维数组,你可以将数组定义为全局数组,此时会自动初始化为0,或者是在main函数中
int dp[0][0] = {0};
即可
然后你会发现如果初始化全部都为0了,那怎么状态转移,所有的情况都将是0啊
所以你需要先定义最初的状态,你会发现在第一个位置从0盆到a[1]盆都会只有一种情况
将其都定为1即可。
下面贴个代码:
#include<stdio.h>
#include<string.h>
#define mod 1000007
int _min(int c, int b){
return c < b ? c : b;
}
int main()
{
int n, m, i, j, k;
int dp[105][105], a[105];
memset(dp, 0, sizeof(dp));
scanf("%d %d", &n, &m);
for(i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(i = 0; i <= a[1]; i++)
dp[1][i] = 1;
for(i = 2; i <= n; i++)
for(j = 0; j <= m; j++){
int t = _min(a[i], j);
for(k = 0; k <= t; k++)
dp[i][j] = (dp[i][j] + dp[i-1][j-k]) % mod;
}
printf("%d", dp[n][m]);
return 0;
}
ps:C++中#include<algorithm>自带min函数