摆花——01背包

P1077 [NOIP2012 普及组] 摆花 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

很很很基础的一道01背包问题,但是对目前的我来说还是有亮点的。

 

状态表示:前i种花共j盆的摆放方案数量

状态计算:

  1.如果第i种花不摆:f[i,j]=f[i-1,j]

  2.如果第i种花摆:

    遍历第i种花能摆放摆放的数量,f[i,j]=sum(f[i-1,j-k])   k的范围是从0到a[i]

  嘿嘿嘿,这样一看就变成01背包咯

  直接对j倒着for循环,把二维变成一维。

1 for(int i=1;i<=n;i++)
2     {
3         for(int j=m;j>=0;j--)
4         {
5             int len=min(a[i],j);
6             for(int k=1;k<=len;k++)
7                 f[j]=(f[j]+f[j-k])%mod;
8         }
9     }

  注意第六行k的循环。裸的01背包是没有这个for循环的,因为这个物品只有0或1,但是这道题每种花的数量不止1个,所以我们需要遍历每种花的数量。

  问题:为什么k从1开始循环,明明第i种花还可以不选,这样k应该是0呀。

  回答:因为当k=1的时候,括号中的f[j]就是f[i-1,j]即不选第i种花时的方案。

  问题:为什么len是a[i],j的最小值

  回答:因为f[j]是f[j-k]的总和,k的范围是0到a[i],那么我们就要保证j-k不是负值,所以k要小于等于j,并且k的范围是0到a[i],所以k要小于等于min ( a [ i ] , j )。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=200,mod=1000007;
 4 int n,m,a[N],f[N];
 5 
 6 int main()
 7 {
 8     scanf("%d%d",&n,&m);
 9     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
10     
11     f[0]=1;
12     for(int i=1;i<=n;i++)
13     {
14         for(int j=m;j>=0;j--)
15         {
16             int len=min(a[i],j);
17             for(int k=1;k<=len;k++)
18                 f[j]=(f[j]+f[j-k])%mod;
19         }
20     }
21     
22     printf("%d\n",f[m]);    
23     
24     return 0;
25 }
View Code

 

posted @ 2022-04-03 16:46  wellerency  阅读(24)  评论(0编辑  收藏  举报