1. 程式人生 > >[洛谷][DP]小A點菜

[洛谷][DP]小A點菜

小A點菜

Description

uim神犇拿到了uoira(鐳牌)後,立刻拉著基友小A到了一家……餐館,很低端的那種。

uim指著牆上的價目表(太低階了沒有選單),說:“隨便點”。

不過uim由於買了一些輔(e)輔(ro)書,口袋裡只剩MM元(M \le 10000)(M10000)。

餐館雖低端,但是菜品種類不少,有NN種(N \le 100)(N100),第ii種賣a_iai(a_i \le 1000)(ai1000)。由於是很低端的餐館,所以每種菜只有一份。

小A奉行“不把錢吃光不罷休”,所以他點單一定剛好吧uim身上所有錢花完。他想知道有多少種點菜方法。

由於小A肚子太餓,所以最多隻能等待11秒。

Input

第一行是兩個數字,表示NN和MM。

第二行起NN個正數a_iai(可以有相同的數字,每個數字均在10001000以內)。

Output

一個正整數,表示點菜方案數,保證答案的範圍在intint之內。

Examples

Input

4 4
1 1 2 2

Output

3

 

正確解法:

原本只會做簡單的01揹包,然後這道題讓我輸出方案數,弄懵了我。

其實看似輸出方案數,本質上都是跟01揹包一樣的,重點是狀態的確立,以及動態轉移方程。

我們把 f[i][j] 看作 i 道菜 j 錢的方案數。

當數到第 i 道菜時,它的方案數就等於 要這道菜 加上 不要這道菜 的方案個數。

f[i][j]=f[i-1][j]+f[i-1][j-a[i]];

最後就是邊界值,如果當前的錢恰好等等於這道菜的錢,那麼就只能點這一道菜。

f[i-1][0]=1;

最後最後就簡單的把這個變成一維就好了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<map>
 6 #include<set>
 7 #include<algorithm>
 8
#include<cmath> 9 #include<cstdlib> 10 using namespace std; 11 int n, m; 12 int a[150]; 13 int f[10100]; 14 void init() 15 { 16 scanf("%d %d",&n,&m); 17 for (int i = 1; i <= n; i++) 18 scanf("%d",&a[i]); 19 } 20 void solve() 21 { 22 f[0] = 1; 23 for (int i = 1; i <= n; i++) 24 for (int j = m; j >= a[i]; j--) 25 f[j] += f[j - a[i]]; 26 } 27 void print() 28 { 29 printf("%d\n",f[m]); 30 } 31 int main() 32 { 33 init(); 34 solve(); 35 print(); 36 return 0; 37 }
View Code