hdu2065(母函数)

排列组合

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1726    Accepted Submission(s): 724


Problem Description
有n种物品,并且知道每种物品的数量。要求从中选出m件物品的排列数。例如有两种物品A,B,并且数量都是1,从中选2件物品,则排列有"AB","BA"两种。
 

Input
每组输入数据有两行,第一行是二个数n,m(1<=m,n<=10),表示物品数,第二行有n个数,分别表示这n件物品的数量。
 

Output
对应每组数据输出排列数。(任何运算不会超出2^31的范围)
 

Sample Input
   
   
   
   
2 2 1 1
 

Sample Output
   
   
   
   
2
 

Author
xhd
 

Recommend
xhd
 


此题AB与BA属于不同的排列组合,故不应简单地用普通的生成函数,而应该用可以处理排列组合的指数型生成函数。公式及原理见转载的大牛博客。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;

int n,m;
int num[10];
double a[100];
double b[100];

double fun(int s)
{
	int i;
	double sum=1;
	for(i=2;i<=s;i++)
		sum*=i;
	return sum;
}

void Generating_function()
{
	int i,j,k;
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	a[0]=1;
	for(i=1;i<=n;i++)
	{
		for(j=0;j<=m;j++)
		{
			for(k=0;k<=num[i]&&k+j<=m;k++)
				b[k+j]+=a[j]*1.0/fun(k);
		}
		memcpy(a,b,sizeof(b));
		memset(b,0,sizeof(b));
	}
}

int main()
{
	int i;
	while(~scanf("%d%d",&n,&m))
	{
		for(i=1;i<=n;i++)
			scanf("%d",&num[i]);
		Generating_function();

		printf("%0.lf\n",a[m]*fun(m));
	}
	return 0;
}


 

你可能感兴趣的:(数学)