P1077 [NOIP2012 普及组] 摆花
P1077
首先二维数组的DP比较好想,设f(i,j)表示前i种花摆了j盆的方案数,方程为\(f(i,j) = \sum_{k = 0}^{a[i]} f(i - 1,j -k)\)
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e6 + 7;
int n, m, a[105], f[105][105];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> a[i];
f[0][0] = 1;
for (int i = 1; i <= n; i ++)
for (int j = 0; j <= m; j ++)
for (int k = 0; k <= min(j, a[i]); k ++)
f[i][j] = (f[i][j] + f[i - 1][j - k]) % mod;
cout << f[n][m];
}
接着我们可以优化成一维数组,因为当前f[i]只与f[i - 1]有关。
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e6 + 7;
int n, m, a[105], f[105];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> a[i];
f[0] = 1;
for (int i = 1; i <= n; i ++)
for (int j = m; j >= 0; j--)
for (int k = 1; k <= min(a[i], j); k ++)
f[j] = (f[j] + f[j - k]) % mod;
cout << f[m];
}
不难发现这种形式和背包(分组背包)极其相似,我们其实可以这样转化题目:有n种花,每种花有a[i]种取法(1~a[i]),求最后得到m盆花的方案数。
因为不同方案下,每种花只有1种取法,这就和分组背包极其相似了,最外层枚举种数,然后倒序枚举盆数,最内层枚举该种花的取法。
反思:
我一开始看到题目就以为是多重背包的题,结果半天搞不出来,其实最重要的就是跟随题意一步步分析,不要想当然地以为是什么板子。