HDU 2152 选课时间(题目已修改,注意读题) (母函数)

选课时间(题目已修改,注意读题)

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2026    Accepted Submission(s): 1612

Problem Description
又到了选课的时间了,xhd看着选课表发呆,为了想让下一学期好过点,他想知道学n个学分共有多少组合。你来帮帮他吧。(xhd认为一样学分的课没区别)
 

 

Input
输入数据的第一行是一个数据T,表示有T组数据。 每组数据的第一行是两个整数n(1 <= n <= 40),k(1 <= k <= 8)。 接着有k行,每行有两个整数a(1 <= a <= 8),b(1 <= b <= 10),表示学分为a的课有b门。
 

 

Output
对于每组输入数据,输出一个整数,表示学n个学分的组合数。
 

 

Sample Input
2
2 2
1 2
2 1
40 8
1 1
2 2
3 2
4 2
5 8
6 9
7 6
8 8
 

 

Sample Output
2
445
 

 

Author
xhd
 

 

Source
 

 

Recommend
lcy
 
 

现在以上面的第二种情况每种种类个数无限为例,给出模板

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

#include <iostream>

using namespace std;

// Author: Tanky Woo

// www.wutianqi.com

const int _max = 10001; 

// c1是保存各项质量砝码可以组合的数目

// c2是中间量,保存没一次的情况

int c1[_max], c2[_max];   

int main()

{	//int n,i,j,k;

	int nNum;   // 

	int i, j, k;

 

	while(cin >> nNum)

	{

		for(i=0; i<=nNum; ++i)   // ---- ①

		{

			c1[i] = 1;

			c2[i] = 0;

		}

		for(i=2; i<=nNum; ++i)   // ----- ②

		{

 

			for(j=0; j<=nNum; ++j)   // ----- ③

				for(k=0; k+j<=nNum; k+=i)  // ---- ④

				{

					c2[j+k] += c1[j];

				}

			for(j=0; j<=nNum; ++j)     // ---- ⑤

			{

				c1[j] = c2[j];

				c2[j] = 0;

			}

		}

		cout << c1[nNum] << endl;

	}

	return 0;

}

 

 

我们来解释下上面标志的各个地方:(***********!!!重点!!!***********)

①  、首先对c1初始化,由第一个表达式(1+x+x^2+..x^n)初始化,把质量从0到n的所有砝码都初始化为1.

②  、 i从2到n遍历,这里i就是指第i个表达式,上面给出的第二种母函数关系式里,每一个括号括起来的就是一个表达式。

③、j 从0到n遍历,这里j就是(前面i個表达式累乘的表达式)里第j个变量,(这里感谢一下seagg朋友给我指出的错误,大家可以看下留言处的讨论)。如(1+x)(1+x^2)(1+x^3),j先指示的是1和x的系数,i=2执行完之后变为
(1+x+x^2+x^3)(1+x^3),这时候j应该指示的是合并后的第一个括号的四个变量的系数。

④ 、 k表示的是第j个指数,所以k每次增i(因为第i个表达式的增量是i)。

⑤  、把c2的值赋给c1,而把c2初始化为0,因为c2每次是从一个表达式中开始的。

 

初学者请阅读:http://www.wutianqi.com/?p=596

 

 
 
#include<iostream>

#include<cstdio>

#include<cstring>



using namespace std;



const int N=50;



int c1[N],c2[N],score[10];



int main(){



    //freopen("input.txt","r",stdin);



    int t,n,m;

    scanf("%d",&t);

    while(t--){

        scanf("%d%d",&n,&m);

        for(int i=0;i<N;i++){

            c1[i]=0;

            c2[i]=0;

        }

        memset(score,0,sizeof(score));

        int a,b;

        for(int i=1;i<=m;i++){

            scanf("%d%d",&a,&b);

            score[a]=b;

        }

        c1[0]=1;

        for(int i=1;i<=m;i++){

            for(int j=0;j<=n;j++)

                for(int k=0;k<=score[i] && j+k*i<=n;k++)

                    c2[j+k*i]+=c1[j];

            for(int j=0;j<=n;j++){

                c1[j]=c2[j];

                c2[j]=0;

            }

        }

        printf("%d\n",c1[n]);

    }

    return 0;

}

 

你可能感兴趣的:(HDU)