擺花——01揹包
阿新 • • 發佈:2022-04-03
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 forView Code(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 }