1. 程式人生 > 其它 >擺花——01揹包

擺花——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