摆花——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 }