组合数学之母函数

//老版母函数
//首先用c1,c2两个数组,c1[j]表示j块钱有c1[j]中表达方式
//c1[0]=1,c2 0
//关键for循环
for (int i = 0; i < n; ++i)//该循环是指每*种*货币一个个的放进去,共n种
{
	for (int j = 0; j <= p; ++j)//这里是c1数组的循环,c1的数组界p
	{
		for (int k = 0; k <= num[i] && k*price[i] + j <= x; ++k)//将第i种货币放k张进去,该种货币最多num[i]个,price[i]表示该货币的价值
		{
			c2[j + k*price[i]] = c1[j];//更新j+k*price[i]的表示方式的个数并且保存在c2中
		}
		
	}
	for (int j = 0; j <= p; ++j)//一种货币放完,开始放下一种货币之前要“初始化”
	{
		c1[j] = c2[j];
		c2[j] = 0;
	}
}
//指数型母函数
//与老版母函数类似
//同样c1,c2两个数组,并且是同样的含义,c1[j]表示j快钱有c1[j]中表达方式
//同样的初始化c1[0]=1;表示0块钱必有一种表达方式
//关键for循环
for (int i = 0; i < n; ++i)//将每种货币放入,货币共n种
{
	for (int j = 0; j <= p; ++j)//与老版相同c1数组,界限为p
	{
		for (k = 0; k <= num[i] && k*price[i] <= x; ++k)//该种货币从0开始放入k个,大多数情况下price权全为1,例如下面的例题
		{
			c2[j+k*price[i]]+=c1[j]/p[j]//与旧版母函数唯一区别,注意
									   //理解方式旧版:1+x^1*1+x^2*1+x^3*1+x^4*1...x的次方代表要表达多少钱,前面的系数表示该钱的表达方式有多少种
										//例如x^1,表示1快钱有1中表达方式,2*x^2表示两块钱有2中表达方式
										//新版母函数是1+x^1/p[1]+x^2/p[2]...其中p存放每个数的阶乘
										//x^1/p[1]可以看作1块钱有1/p[1]中表达方式
										//所以说,像旧版母函数,每种新放入的货币的像1,2,3快钱都只有一种表达方式所以是c2[j+k*price]
										//+=c1[j]*1;只需要在原有j快钱的表达方式*乘以新加入钱的表达方式
										//而新版母函数新加入的钱有1/p[j]中表达方式,所以是c1[j]/p[j];ok
		}
	}
	for (int j = 0; j <= p; ++j)
	{
		c1[j] = c2[j];
		c2[j] = 0;
	}


}

例题

排列组合

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 38   Accepted Submission(s) : 12

Font: Times New Roman | Verdana | Georgia

Font Size:  

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
AC代码

#include
#include
#include
using namespace std;

long long x[15];

int main()
{
	x[0] = 1;
	x[1] = 1;
	for (int i = 2; i != 15; ++i)
		x[i] = i*x[i - 1];
	double c1[15];
	double c2[15];
	int z[15];
	
	int n, m;
	while (cin >> n >> m)
	{
		memset(c1, 0.0, sizeof(c1));
		memset(c2, 0.0, sizeof(c2));
		c1[0] = 1;
		for (int i = 0; i != n; ++i)
			cin >> z[i];
		for (int i = 0; i != n; ++i)
		{
			for (int j = 0; j <= m; ++j)
			{
				for (int k = 0; k <= z[i] && k + j <= m; ++k)
					c2[k + j] += c1[j] / x[k];
			}
			for (int j = 0; j <= m; ++j)
			{
				c1[j] = c2[j];
				c2[j] = 0;
			}
		}
		//printf("%.0lf\n", c1[m] * x[m]);//四舍五入取整
		//cout << round(c1[m]*x[m]);
		//cout << floor(c1[m] * x[m] + 0.5);
	}
	system("pause");
	return 0;
	
}








你可能感兴趣的:(C++,Dynamic,programming)