POJ1664 放苹果 (母函数)
放苹果
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 37515 | Accepted: 23090 |
Description
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。
Input
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
Output
对输入的每组数据M和N,用一行输出相应的K。
Sample Input
1 7 3
Sample Output
8
思路:多校见过类似的题目,简单母函数题目,不过比赛的时候,直接给出了解题分析:用的递归写的,感觉不是太理解。
递归:(见注释)
1 #include <iostream> 2 #include <stdio.h> 3 #include <math.h> 4 #include <string.h> 5 #include <stdlib.h> 6 #include <string> 7 #include <vector> 8 #include <set> 9 #include <map> 10 #include <queue> 11 #include <algorithm> 12 #include <sstream> 13 #include <stack> 14 using namespace std; 15 #define mem(a,b) memset((a),(b),sizeof(a)) 16 #define mp make_pair 17 #define pb push_back 18 #define fi first 19 #define se second 20 #define sz(x) (int)x.size() 21 #define all(x) x.begin(),x.end() 22 typedef long long ll; 23 const int inf = 0x3f3f3f3f; 24 const ll INF =0x3f3f3f3f3f3f3f3f; 25 const double pi = acos(-1.0); 26 const double eps = 1e-5; 27 const ll mod = 1e9+7; 28 //head 29 30 int fun(int m, int n) { 31 if(n == 1 || m == 0)//如果剩1个盘子 || 没有苹果可以放 32 return 1; 33 if(n > m)//如果盘子多于苹果,相当于去除多余盘子 34 return fun(m, m); 35 else //前者:所有盘子都有苹果,相当于每一个盘子都拿掉一个。后者:至少有一个空盘子 36 return fun(m-n, n) + fun(m, n-1); 37 } 38 39 int _, n, m; 40 int main() { 41 for(scanf("%d", &_);_;_--) { 42 scanf("%d%d", &m, &n); 43 printf("%d\n", fun(m, n));//m个苹果,n个盘子 44 } 45 }
母函数:
理解母函数就是一道裸题,写出各个式子,然后计算,系数即为答案。
有一点比较难理解。我其实一直以为是k++,因为每一项都是
,但是题目说了
1,1,5 和 5,1,1是同一种,所以k++会重复,所以用
,这样保证了不会重复。
可以理解为拿几个1,拿几个5,这样就避免了重复。
推荐博客:https://www.cnblogs.com/dolphin0520/archive/2012/11/07/2755080.html
母函数计算理解:http://blog.chinaunix.net/uid-26602509-id-3193699.html
1 #include <iostream> 2 #include <stdio.h> 3 #include <math.h> 4 #include <string.h> 5 #include <stdlib.h> 6 #include <string> 7 #include <vector> 8 #include <set> 9 #include <map> 10 #include <queue> 11 #include <algorithm> 12 #include <sstream> 13 #include <stack> 14 using namespace std; 15 #define mem(a,b) memset((a),(b),sizeof(a)) 16 #define mp make_pair 17 #define pb push_back 18 #define fi first 19 #define se second 20 #define sz(x) (int)x.size() 21 #define all(x) x.begin(),x.end() 22 typedef long long ll; 23 const int inf = 0x3f3f3f3f; 24 const ll INF =0x3f3f3f3f3f3f3f3f; 25 const double pi = acos(-1.0); 26 const double eps = 1e-5; 27 const ll mod = 1e9+7; 28 //head 29 int c1[20], c2[20];//c1存展开式的系数,c2计算时保存 30 int _, m, n; 31 int main() { 32 for(scanf("%d", &_);_;_--) { 33 scanf("%d%d", &m, &n); 34 for(int i = 0; i <= m; i++) {//初始化第一个表达式 35 c1[i] = 1; 36 c2[i] = 0; 37 } 38 for(int i = 2; i <= n; i++) {//从第二个开始 39 for(int j = 0; j <= m; j++) {//已经累乘的式子的第j项 40 for(int k = 0; k+j <= m; k += i) {//k += i !!! 41 c2[j+k] += c1[j]; 42 } 43 } 44 for(int i = 0; i <= m; i++) {//更新 45 c1[i] = c2[i]; 46 c2[i] = 0; 47 } 48 } 49 printf("%d\n", c1[m]);//次数为m的系数即为答案 50 } 51 }
埋骨何须桑梓地,人生无处不青山