Stirling公式也叫做斯特林公式,是用来取N! 的近似值。
在编程中,也用到了Stirling数的思想来解决以下问题。
把n个物体排成k个非空循环的方法数目。
S(n,0)=0(n>=1)
n个物体不可能不形成环,因为一个物体就能形成环
S(1,1)=1(n>=1)
一个物体能形成一个环
S[i][j]=S(i-1,j-1)+(i-1)S(i-1,j) (1<=j<=i<=n)
具体看例子
对于第一类stirling公式递推关系的理解
第n个物体单独占一个环时其他元素的情况:S(n-1,k-1);第n个物体加入其他环时的情况,(n-1)S(n-1,k),这个物体可以加到第i个物体的左边,所以有n-1种可能。
#include
long long arr[25][25];
long long Stirling1(int n,int k)
{
if(k==0 || k>n)
return 0;
if(n==1 && k==1)
return 1;
return Stirling1(n-1,k-1)+(n-1)*Stirling1(n-1,k);
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
long long ans=Stirling1(n,k);
printf("%lld",ans);
return 0;
}
#include
long long S[25][25];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
S[1][1]=1;
for(int i=2;i<=n;i++)
{
for(int j=1;j<=i;j++)
S[i][j]=S[i-1][j-1]+(i-1)*S[i-1][j];
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(j<n) printf("%lld ",S[i][j]);
else printf("%lld\n",S[i][j]);
}
}
printf("%lld",S[n][k]);
return 0;
}
把n个苹果放入m个相同的盘子中,不允许盘子为空,请问总共有多少种方法?
S(n,k)=0 (k>n or k=0)
可以想到,将10个苹果放入100个盘是不现实的(k>n),没有盘子也是不现实的(k=0)
S(n,1)=S(n,n)=1
将所有苹果放入一个盘子只有一种情况(k=1),将2个苹果放入2个盘子只有一种情况(n=k)
S(n,k)=S(n-1,k-1)+kS(n-1,k)
这个递推方程下面有解释。
对于第二类stirling公式递推关系的理解:
第n个元素单独占一个子集时其他元素的情况:S(n-1,k-1);第n个元素和其他元素呆在同一个子集时有kS(n-1,k)种情况。所以结果就是S(n-1,k-1)+kS(n-1,k)
举个例子来说,当n=4,m=3时,S(4,3)=?。
根据Stirling数公式得S(4,3)=S(3,2)+3*S(3,3)。
(1).分析拿3个苹果放到2个盘子的可能,
{1,{2,3}}————{1,{2,3},4}在将苹果4放入一个盘中
{{1,3},2}————{{1,3},2,4}在将苹果4放入一个盘中
{{1,2},3}————{{1,2},3,4}在将苹果4放入一个盘中
(2).分析拿3个苹果放入3个盘子的可能,
{1,2,3}————{{1,4},2,3}现在是三个盘子都装满,还有一个苹果放入三个盘中的情况
————{1,{2,4},3}
————{1,2,{3,4}}
注意:这里是用Stirling数来模拟N!算法,当然数字不能超过25,如果超过25,题目都会说要对结果进行取模处理
#include
long long Stirling(int n,int m)
{
if(m==0 || n<m)//不符合题意
return 0;
if(m==1 || n==m)//只有一种方法.
return 1;
return Stirling(n-1,m-1)+m*Stirling(n-1,m); //递归分治
}
int main()
{
int n,m;//n表示苹果数,m表示盘子数。
scanf("%d%d",&n,&m);
long long ans=Stirling(n,m);
printf("%lld",ans);
return 0;
}
时间复杂度为2的n次方
#include
long long s[50][50];//表示s[n][m]
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
s[i][1]=1;
s[i][i]=1;
for(int j=1;j<i;j++)
s[i][j]=s[i-1][j-1]+(long long)j*s[i-1][j];//这里的n不能超过25,由于这里算的是一个组合
}
printf("%lld\n",s[n][m]);
return 0;
}
时间复杂度为n²