算法课-母函数专题

【生成函数解析】

https://blog.csdn.net/Z_sea/article/details/86529635

由于CSDN更新过好几个版本,导致一些图片的丢失,但一点都不影响解析生成函数。

 


 

利用D题的选课时间作为模版。

给定m个物品的价格和数量,构成价值为n的方案数

 

 1 #include<cstdio>
 2 #include<algorithm>
 3 
 4 using namespace std;
 5 const int N = 50 ;
 6 int n , m ;
 7 int a[N] , b[N] , c[N] ;
 8 int f[N] , tmp[N] ;
 9 int main()
10 {
11     int T ;
12     scanf("%d",&T);
13     while( T-- ){
14                 //初始化
15         for( int i = 0 ; i < N ; i++ )  tmp[i] = f[i] = 0 ;
16         f[0] = 1; 
17         scanf("%d%d",&n,&m);
18         
19         int Highest_Pow = 0 , Limit;
20         //枚举物品
21         for( int i = 1 ; i <= m ; i++ ){
22             scanf("%d%d",&a[i],&b[i]);
23 
24             Limit = min( Highest_Pow , n );
25 
26             //枚举第一个括号中的次幂
27             for( int j = 0 ; j <= Limit ; j++ ){
28                 //枚举第二个括号中的个数,通过它的价值a[i],枚举每一项指数 应为k*a[i]
29                 for( int k = 0 ; j + k * a[i] <= n && k <= b[i] ; k++ ){
30                     tmp[ j + k*a[i] ] += f[j];
31                 }
32             }
33 
34             //更新最高次幂
35             Highest_Pow += a[i] * b[i] ;
36             Limit = min( Highest_Pow , n );
37             for( int j = 0 ; j <= Limit ; j++ ){
38                 f[j] = tmp[j] ;
39                 tmp[j] = 0 ;
40             }
41         }
42         printf("%d
",f[n]);
43     }
44     return 0;
45 }
模版1
 1 #include<cstdio>
 2 #include<algorithm>
 3 
 4 using namespace std;
 5 const int N = 50 ;
 6 int n , m ;
 7 int a[N] , b[N] , c[N] ;
 8 int f[N] , tmp[N] ;
 9 int main()
10 {
11     int T ;
12     scanf("%d",&T);
13     while( T-- ){
14                 //初始化
15         for( int i = 0 ; i < N ; i++ )  tmp[i] = f[i] = 0 ;
16         f[0] = 1;
17         scanf("%d%d",&n,&m);
18         
19         int Highest_Pow = 0 , Limit;
20         //枚举物品
21         for( int i = 1 ; i <= m ; i++ ){
22             scanf("%d%d",&a[i],&b[i]);
23 
24             Limit = min( Highest_Pow , n );
25 
26             //枚举第一个括号中的次幂
27             for( int j = 0 ; j <= Limit ; j++ ){
28                 //枚举第二个括号中的个数,通过它的价值a[i],枚举每一项指数 应为k*a[i]
29                 for( int k = 1 ; j + k * a[i] <= n && k <= b[i] ; k++ ){
30                     tmp[ j + k*a[i] ] += f[j];
31                 }
32             }
33 
34             //更新最高次幂
35             Highest_Pow += a[i] * b[i] ;
36             Limit = min( Highest_Pow , n );
37             for( int j = 0 ; j <= Limit ; j++ ){
38                 f[j] += tmp[j] ;
39                 tmp[j] = 0 ;
40             }
41         }
42         printf("%d
",f[n]);
43     }
44     return 0;
45 }
模版2

A - Holding Bin-Laden Captive!

【题目来源】HDU - 1085

【题意】
        给定n1,n2,n3分别代表硬币面值为1,2,5元的数量
        请输出由这些硬币 凑不成的最小正整数?
    例如:
        有1个面值为1元的硬币。
        有1个面值为2元的硬币。
        有3个面值为5元的硬币。
        
        即可构成:{1,2,3,5,6,7,8,10,11,12,13,15,16,17,18}
        集合中凑不成的最小正整数为 4.
【题解】
        基本上就是母函数(生成函数)的模板题
        根据题目的样例构造出
        ( x^0 + x^1 ) * ( x^0 + x^2 + x^4 ) * ( x^0 + x^5 + x^10 + x^15 )
        请大家用草稿纸手动算一下上述式子。
        
        你就会发现能凑出来的数字会是拥有指数为{1,2,3,5,6,7,8,10,11,12,13,15,16,17,18}的多项式。而我们想要找的答案只需要遍历哪个指数未出现过即可。
        
        这种题型被称为:普通型的母函数(生成函数)
        其特点为:给定 ”面值” 和 “数量” 问其“构成的方案数”或“能否构成”。
        而这个题目是:固定面值,给出数量,问起能否构成。
        
        算法复杂度O(n^3)
        计算过程就是模拟多项式乘法,()*()两个多项式之间进行乘法运算。
 1 #include<stdio.h>
 2 const int N = 8e3 + 10 ;
 3 int weight[3] = { 1 , 2 , 5 };
 4 int num[3] ;
 5 int f[N] ;
 6 int tmp[N] ;
 7 int main()
 8 {
 9     while( scanf("%d%d%d",&num[0],&num[1],&num[2]) , (num[0]+num[1]+num[2]) ){
10         //初始化
11         f[0] = 1 ;
12         for( int i = 1 ; i < N ; i++ ) f[i] = 0 ;
13 
14         //枚举第一个括号
15         for( int i = 1 ; i <= num[0] ; i++ ) f[i] = 1 ;
16 
17         int Highest_Pow = 0 ;
18 
19         //第一层枚举 硬币种类
20         for( int i = 0 ; i < 3 ; i ++ ){
21             //第二层枚举  第一个括号中 从0次幂到最高次幂
22             for( int j = 0 ; j <= Highest_Pow ; j ++ ){
23                 //第三层枚举 第二个括号中的数量
24                 for( int k = 1 ; k <= num[i] ; k++ ){
25                     f[ j + k * weight[i] ] |= f[j];
26                 }
27             }
28             //更新最高次幂
29             Highest_Pow += weight[i] * num[i] ;
30         }
31 
32         for( int i = 1 ; i < N ; i++ ){
33             if( !f[i] ){
34                 printf("%d
",i);
35                 break;
36             }
37         }
38     }
39     return 0;
40 }
Holding Bin-Laden Captive!-母函数
扩展做法-多重背包
    我们习惯做的是01背包问题,多重背包仅仅是多增加了一个维度:"物品数量"
    任何"普通型母函数问题" 都可以转化成 "多重背包问题"
    多重背包模型会比母函数更加好写。
    问题转化是一样的,都是根据生成函数的特点而设计。
    仅仅是计算的角度不一样。    
    同时,多重背包灵活性体现在复杂度
    朴素做法 O(N^3) -> 二进制优化 O(N * V *logN ) -> 单调队列优化 O(N * V)
 1 //扩展(多重背包做法-朴素做法)
 2 #include<stdio.h>
 3 const int N = 8e3 + 20 ;
 4 
 5 int f[N];
 6 int num[3];
 7 int weight[3] = { 1 , 2 , 5 };
 8 
 9 int main()
10 {
11     while( scanf("%d%d%d",&num[0],&num[1],&num[2]) , ( num[0] + num[1] + num[2] ) ){
12         f[0] = 1 ;
13         for( int i = 1 ; i < N ; i++ ) f[i] = 0 ;
14 
15         int V = num[0] + num[1] * 2 + num[2] * 5 ;
16                 //枚举物品个数
17         for( int i = 0 ; i < 3 ; i ++ ){
18             //枚举每个物品的重量
19             for( int j = V ; j >=  weight[i]; j -- ){
20                 //在j容量限制下枚举物品个数,同时进行01背包处理
21                 for( int k = 1 ; k <= num[i] ; k++ ){
22                     if( j - k * weight[i] >= 0 ){
23                         f[j] |= f[j - k * weight[i]] ;
24                     }
25                 }
26             }
27         }
28         
29         for( int i = 1 ; i < N ; i++ ){
30             if( !f[i] ){
31                 printf("%d
",i);
32                 break;
33             }
34         }
35     }
36     return 0;
37 }
扩展(多重背包做法-朴素做法)

B - Big Event in HDU

【题目来源】HDU - 1171

【题意】
    给定n个物品的“价值”,“数量”
    请问如果尽可能划分出两堆物品 ,要求 两堆物品间价值之差 尽可能小。
    例如:
    有1个物品价值为10
    有2个物品价值为20
    有1个物品价值为30    
    通过划分两堆物品 {10,30} = 40 ,{20,20} = 40
    所以答案为 40 40
    划分两堆物品如果价值不同,请先输出价值大的一堆,后输出价值小的一堆
【生成函数做法】
    和上一个题目类似
    给定物品的价值和数量,问是否存在尽可能靠近total/2的值。
    首先处理好输入,初始化工作。
    然后进行生成函数模板代入。
    最后遍历,找出尽可能靠近total/2的情况
 1 #include<cstdio>
 2 const int N = 5e6 + 10;
 3 const int M = 1e3 + 10;
 4 int f[N] ;
 5 int num[M] , w[M] ;
 6 int main()
 7 {
 8     int n , Highest_Pow , total ;
 9     while( scanf("%d",&n) ,( n>0 ) ){
10         total = 0 ;
11         for( int i = 0 ; i < n ; i ++ ){
12             scanf("%d%d",&w[i] , &num[i] );
13             total += w[i] * num[i] ;
14         }
15         for (int i = 1 ; i <= total / 2 ; i++ ) f[i] = 0 ;
16         f[0] = 1 ;
17         Highest_Pow = 0 ;
18 
19         for( int i = 0 ; i < n ; i ++ ){
20             for( int j = 0 ; j <= Highest_Pow ; j ++ ){
21                 for( int k = 1 ; k <= num[i] ; k++ ){
22                     f[j+k*w[i]] |= f[j] ;
23                 }
24             }
25             Highest_Pow += w[i] * num[i] ;
26         }
27         for( int i = total/2 ; i >= 0 ; i--){
28             if( f[i] ){
29                 printf("%d %d
",total-i,i);
30                 break;
31             }
32         }
33     }
34     return 0 ;
35 }
Big Event in HDU-母函数做法
【01背包做法】
    经典的背包问题,01背包
        
    首先限制背包容量为总容量的一半。
    然后把所有的物品离散化,同时进行01背包处理后。
    答案为: {total - f[V] , f[V]}
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 const int N = 5e6 + 10 ;
 6 const int M = 1e3 + 10 ;
 7 int f[N];
 8 int w[M];
 9 int num[M];
10 int main()
11 {
12     int n , V , total ;
13     while( scanf("%d",&n) , ( n > 0 ) ){
14         
15         total = V = 0 ;
16         
17         for( int i = 0 ; i < n ; i++ ){
18             scanf("%d%d",&w[i] , &num[i] );
19             total += w[i] * num[i] ;
20         }
21         V = total / 2 ;
22 
23         for( int i = 0 ; i <= V ; i ++ ) f[i] = 0 ;
24 
25         for( int i = 0 ; i < n ; i++ ){
26             while( num[i]-- ){
27                 for( int j = V ; j >= w[i] ; j-- ){
28                     f[j] = max( f[j] , f[j-w[i]] + w[i] );
29                 }
30             }
31         }
32         
33         printf("%d %d
",total - f[V] , f[V] );
34     }
35     return 0;
36 }
Big Event in HDU-01背包做法

C - Square Coins

【题目来源】HDU - 1398

【题意】
    给定价值为1,49……28917^2)的硬币
    给定一个值,请问有多少种构造的方法?
    例如:
        10 = 1 + 1 …… + 1
        10 = 1 + 1 + 1 + 1 + 1 + 1 + 4 
        10 = 1 + 1 + 4 + 4
        10 = 1 + 9
    答案就是4
【生成函数做法】
    这个题目和课堂上讲的例题一模一样,仅仅是面值发生改变,其余的都没有变。
    该题的普通母函数的结构为 "面值固定""数量不定",求解构成某个数值的方案数?
 1 #include<cstdio>
 2 using namespace std;
 3 const int M = 305 ;
 4 const int N = 20 ;
 5 int f[M];
 6 int v[N];
 7 int tmp[M];
 8 void Init(){
 9     for( int i = 0 ; i < 17 ; i++ ){
10         v[i] = ( i+1 ) * ( i+1 );
11     }
12     f[0] = 1 ;
13     for( int i = 0 ; i < 17 ; i ++ ){
14         for( int j = 0 ; j <= 300 - v[i] ; j++ ){
15             for( int k = 1 ; j + k*v[i] < M ; k++ ){
16                 tmp[ j+k*v[i] ] += f[j] ;
17             }
18         }
19         for(int j = 1 ; j <= 300 ; j++ ){
20             f[j] += tmp[j] ;
21             tmp[j] = 0;
22         }
23     }
24 }
25 int main(){
26 
27     int n ;
28     Init();
29     while( scanf("%d",&n) , n > 0 ){
30         printf("%d
",f[n]);
31     }
32     return 0;
33 }
Square Coins-母函数
【完全背包做法】
    完全背包 指的是 “物品数量无限”的背包问题
    这个题目其实就是和之前生成函数有所区别在于个数不再受限。
    所以问题可以转变成可取无限多次的背包问题->"完全背包"
 1 #include<cstdio>
 2 using namespace std;
 3 const int M = 305 ;
 4 const int N = 20 ;
 5 int f[M];
 6 int v[N];
 7 int tmp[M];
 8 void Init(){
 9     for( int i = 0 ; i < 17 ; i++ ){
10         v[i] = ( i+1 ) * ( i+1 );
11     }
12     f[0] = 1 ;
13     for( int i = 0 ; i < 17 ; i ++ ){
14         for( int j = v[i] ; j <= 300 ; j++ ){
15             f[j] += f[j-v[i]];
16         }
17     }
18 }
19 int main(){
20 
21     int n ;
22     Init();
23     while( scanf("%d",&n) , n > 0 ){
24         printf("%d
",f[n]);
25     }
26     return 0;
27 }
Square Coins-完全背包做法

D - 选课时间

题目链接:HDU - 2079

【题意】
    给定n门课,每一门课都有相应的学分和数目
    请问构成学分为m的方案有多少种?
【母函数做法】
    和课堂上例题"整数划分问题"一模一样。
    给定“学分”和“数量” 求解某学分的方案数
 1 #include<cstdio>
 2 using namespace std;
 3 const int N = 50 ;
 4 int n , m ;
 5 int a[N] , b[N] , c[N] ;
 6 int f[N] , tmp[N] ;
 7 int main()
 8 {
 9     int T ;
10     scanf("%d",&T);
11     while( T-- ){
12 
13         for( int i = 0 ; i < N ; i++ )  tmp[i] = f[i] = 0 ;
14         f[0] = 1 ;
15 
16         scanf("%d%d",&n,&m);
17         
18         for( int i = 1 ; i <= m ; i++ ){
19             scanf("%d%d",&a[i],&b[i]);
20             for( int j = 0 ; j <= n ; j++ ){
21                 for( int k = 1 ; j + k * a[i] <= n && k <= b[i] ; k++ ){
22                     tmp[ j + k*a[i] ] += f[j];
23                 }
24             }
25             for( int j = 0 ; j <= n ; j++ ){
26                 f[j] += tmp[j] ;
27                 tmp[j] = 0 ;
28             }
29         }
30         printf("%d
",f[n]);
31     }
32     return 0;
33 }
选课时间-母函数
【多重背包做法】
    给定n个物品,给定物品的“价值”和”数量“
    请问构成价值为n的方案数有多少?
 1 #include<cstdio>
 2 using namespace std;
 3 const int N = 50 ;
 4 int f[N] ; 
 5 int a[N] , b[N] ;
 6 int n , m;
 7 int main()
 8 {
 9     int T;
10     scanf("%d",&T);
11     while(T--){
12         scanf("%d%d",&n,&m);
13         for( int i = 0 ; i < m ; i++ ){
14             scanf("%d%d",&a[i],&b[i]);
15         }
16         
17         for( int i = 1 ; i <= n ; i ++ ) f[i] = 0 ;
18         f[0] = 1 ;
19         for( int i = 0 ; i < m ; i ++ ){
20             for( int j = n ; j >= a[i] ; j--){
21                 for( int k = 1 ; k <= b[i] && j - k*a[i] >= 0 ; k++ ){
22                     f[j] += f[j-k*a[i]];
23                 }
24             }
25         }
26         printf("%d
",f[n]);
27     }
28     return 0 ;
29 } 
选课时间-多重背包

E - 找单词

题目来源:HDU - 2082

【题意】
    给定26个字母的数量,每个字母的权值 按顺序排。
    A - 1 , B - 2 …… Z - 26    
    请问由这些数量字母组成的单词价值<=50 的方案数?
【普通型生成函数做法】
    根据题目所给定的数量进行构造生成函数。
    然后模拟多项式乘法,累加系数[1,50]的方案数。
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N = 30 ;
 6 const int M = 50 ;
 7 int f[M+10] ;
 8 int tmp[M+10] ;
 9 int num[N];
10 int main()
11 {
12     int T ;
13     scanf("%d",&T);
14     while( T-- ){
15         for( int i = 1 ; i <= 26 ; i++ )    scanf("%d",&num[i]);
16         for( int i = 0 ; i <= M ; i++ ) f[i] = 0 ; 
17         f[0] = 1 ; 
18         int Highest_Pow = 0 , Limit ;
19         for( int i = 1 ; i <= 26 ; i++ ){
20             Limit = min( Highest_Pow , M );
21             for( int j = 0 ; j <= Limit ; j++ ){
22                 for ( int k = 1 ; k <= num[i] && j + k * i <= M ; k ++ ){
23                     tmp[j+k*i] += f[j];
24                 }
25             }
26             Highest_Pow += num[i] * i ;
27             Limit = min( Highest_Pow , M );
28             for( int j = 0 ; j <= Limit ; j ++ ){
29                 f[j] += tmp[j];
30                 tmp[j] = 0 ;
31             }
32         }
33         int ans = 0 ;
34         for( int i = 1 ; i <= M ; i++ ){
35             ans += f[i] ;
36         }
37         printf("%d
",ans);
38     }
39     return 0;
40 }
找单词-母函数
【多重背包做法】
    给定物品为数量,价值固定,求出价值之和<=50的方案数
 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int N = 55; 
 5 const int M = 50;
 6 int f[N],num[N];
 7 
 8 int main()
 9 {
10     int T; 
11     scanf("%d",&T);
12     while(T--){
13         for( int i = 1 ; i <= 26 ; i ++ ) scanf("%d",&num[i]);
14         for( int i = 1 ; i <= M ; i ++ )    f[i] = 0 ;
15         
16         f[0] = 1 ;
17         for( int i = 1 ; i <= 26 ; i ++ ){
18             for( int j = M ; j >= i ; j-- ){
19                 for( int k = 1 ; k <= num[i] && j - k * i >= 0 ; k ++ ){
20                     f[j] += f[j-k*i];
21                 }
22             }
23         }
24         
25         int ans = 0; 
26         for( int i = 1 ; i <= M ; i ++ ){
27             ans += f[i];
28         }
29         printf("%d
",ans);
30     }
31     return 0;
32 }
找单词-多重背包

F - Crisis of HDU

【题目来源】HDU - 2110

【小结】
    这个题意很难读懂。
    给定n个物品 的价值及数量
    请问  价值为总价值的三分之一 的 方案数?
【题解】
    给出物品的价格及数量。
    首先判断 总价值是否能被3整除。同时计算完后,如果方案数为0还是输出"sorry"。
        
    然后进行套母函数模板或者多重背包的模板即可
【注意】
    取模运算
    (a + b) % mod = a % mod + b % mod
    所以过程中进行模运算不影响最后答案在mod意义下的结果
 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 const int mod = 10000;
 6 const int N = 1e3+10;
 7 
 8 int f[N],a[N],b[N],tmp[N];
 9 int n ;
10 
11 int main()
12 {
13     while( scanf("%d",&n) , (n != 0) ){
14         int total = 0 ;
15         for( int i = 0 ; i < n ; i ++ ){
16             scanf("%d%d",&a[i],&b[i]);
17             total += a[i] * b[i] ;
18         }
19 
20         if( total % 3 != 0 ){
21             printf("sorry
");
22             continue ;
23         }
24 
25         int Highest_Pow = 0 , Limit ;
26         for( int i = 1 ; i <= total / 3 ; i ++ ) f[i] = 0 ;
27         f[0] = 1 ;
28         for( int i = 0 ; i < n ; i ++ ){
29             Limit = min( Highest_Pow , total / 3 );
30             for( int j = 0 ; j <= Limit ; j ++ ){
31                 for( int k = 1 ; k <= b[i] && j + k * a[i] <= total / 3 ; k ++ ){
32                     tmp[ j + k*a[i] ] = ( tmp[j+k*a[i]] + f[j] ) % mod ;
33                 }
34             }
35 
36             Highest_Pow += a[i] * b[i] ;
37             Limit = min( Highest_Pow , total / 3 );
38             for( int j = 0 ; j <= Limit ; j++ ){
39                 f[j] = (f[j] + tmp[j]) % mod ;
40                 tmp[j] = 0 ;
41             }
42         }
43 
44         if( f[ total / 3 ] ){
45             printf("%d
",f[total/3]);
46         }else{
47             printf("sorry
");
48         }
49     }
50     return 0;
51 }
Crisis of HDU-母函数
 1 #include<cstdio>
 2 const int N = 1e3 + 10; 
 3 const int mod = 1e4 ;
 4 int f[N] , a[N] , b[N] ;
 5 
 6 int main()
 7 {
 8     int n ; 
 9     while( scanf("%d",&n) , n ){
10         int sum = 0 ;
11         for( int i = 0 ; i < n ; i++ ){
12             scanf("%d%d",&a[i],&b[i]);
13             sum += a[i] * b[i] ;
14         }
15         for( int i = 1 ; i <= sum / 3 ; i++ ) f[i] = 0; 
16         f[0] = 1 ;
17 
18         for( int i = 0 ; i < n ; i++ ){
19             for( int j = sum / 3 ; j >= a[i] ; j --){
20                 for( int k = 1 ; k <= b[i] && j - k * a[i] >= 0 ; k++ ){
21                     f[j] = ( f[j] + f[j-k*a[i]] ) % mod;
22                 }
23             }
24         }
25         if( sum % 3 || ( sum % 3 == 0 && f[sum/3] == 0 ) ){
26             printf("sorry
");
27         }else{
28             printf("%d
",f[sum/3]);
29         }
30     }
31     return 0;
32 }
Crisis of HDU-多重背包

G - Fruit

【题目来源】HDU - 2152

【题意】
    题目意思是说:价值全为1的物品,然后给出n种不同物品,以及对应的数量。
    但是这个数量是一个范围的概念[A,B],即物品的数量必须是[A,B]之间
    求出组成价值为m的方案数
【题解】
    如果这道题用母函数做,只需要修改题目中所固定的数量即可。
        
    但如果用多重背包来做的话,背包问题默认必须是从某个起始点开始,也就是从0开始进行递推累加方案数。但是如果这个题目的话不能直接套用,但是我们可以技巧性地把问题转移到从0开始。
    数量从[A,B]->[0,B-A],这样的话对应的m也需要减去各组物品的A.
    然后套用模版即可。
 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 const int N = 2e3 + 10 ;
 5 int f[N] , tmp[N] ;
 6 int main()
 7 {
 8     int n , m  , A , B ;
 9     while( scanf("%d%d",&n,&m) != EOF ){
10         memset( f , 0 , sizeof f );
11         scanf("%d%d",&A,&B);
12         for( int i = A ; i <= B ; i++ ) f[i] = 1 ;
13         for( int i = 1 ; i < n ; i ++ ){
14             scanf("%d%d",&A,&B);
15             for( int j = 0 ; j <= m ; j++ ){
16                 for( int k = A ; k <= B && j + k <= m ; k ++ ){
17                     tmp[j+k] += f[j];
18                 }
19             }
20             for( int j = 0 ; j <= m ; j++ ){
21                 f[j] = tmp[j];
22                 tmp[j] = 0 ;
23             }
24         }
25         printf("%d
",f[m]);
26     }
27     return 0;
28 }
Fruit-母函数
 1 #include<cstdio>
 2 #include<cstring>
 3 const int N = 205;
 4 int f[N] , A[N] , B[N];
 5 int main()
 6 {
 7     int n , m ;
 8     while( scanf("%d%d",&n,&m) != EOF){
 9         memset( f , 0 , sizeof f );
10         f[0] = 1; 
11 
12         for( int i = 0 ; i < n ; i++ ){
13             scanf("%d%d",&A[i],&B[i]);
14             m -= A[i];
15             B[i] -= A[i];
16         }
17 
18         for( int i = 0 ; i < n ; i++ ){
19             for( int j = m ; j >= 1 ; j -- ){
20                 for( int k = 1 ; k <= B[i] && j - k >= 0 ; k ++ ){
21                     f[j] += f[j-k];
22                 }
23             }
24         }
25         if( m < 0 ) printf("0
");
26         else printf("%d
",f[m]);
27     }
28     return 0 ;
29 }
Fruit-多重背包
原文地址:https://www.cnblogs.com/Osea/p/12133299.html