zoukankan      html  css  js  c++  java
  • 算法课-母函数专题

    【生成函数解析】

    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-多重背包
  • 相关阅读:
    如何快速定位到DBGrid的某一行!!!急...
    说说设计模式~单件模式(Singleton)
    EF架构~终于自己架构了一个相对完整的EF方案
    .Net——实现IConfigurationSectionHandler接口定义处理程序处理自定义节点
    在LINQ中实现多条件联合主键LEFT JOIN
    从LINQ开始之LINQ to Objects(上)
    WPF控件模板和数据模板
    WPF的ListView控件自定义布局用法实例
    初步探讨WPF的ListView控件(涉及模板、查找子控件)
    LINQ技巧:如何通过多次调用GroupBy实现分组嵌套
  • 原文地址:https://www.cnblogs.com/Osea/p/12133299.html
Copyright © 2011-2022 走看看