【POJ 3088】Push Botton Lock(dp+第二类斯特林数)
Push Botton Lock
Description The Frobozz Magic Lock Company is in the business of manufacturing push button style combination door locks. A push button door lock consists of a number of push buttons B, (1 ≤ B ≤ 11), labeled “1” through “B”. The lock is opened by pressing the correct sequence of button combinations and then turning the doorknob. If the sequence of presses is correct, the door magically opens. A combination consists of 1 or more buttons being pressed simultaneously. A sequence consists of a series of combinations. A sequence must have at least one combination. Once a button has been used in a combination, it may not be used again in the same sequence. In addition, it is not necessary to use all the buttons in a sequence. For example, for B = 8: (1-2-3)(4)(7-8) is a valid sequence with 3 combinations (1-2-3), (4), and (7-8). Note that buttons 5 and 6 are not used in this sequence. (1-2-3)(2-4)(5-6) is not a valid sequence, since button 2 appears in 2 combinations (1-2-3) and (2-4). The CEO of Frobozz, J. Pierpont Flathead, wants you to write a program that determines the number of valid sequences possible for given values of B. The program must be able to process a list of lock orders (datasets) from customers and generate a report showing the order number, the value of B, and the number of valid sequences possible. This list will always contain at least one dataset, but no more than 100 datasets. Reference Materials:
Input The first line of input contains a single integer N, (1 ≤ N ≤ 100), representing the number of datasets that follow. Each dataset consists of a single line of data containing a single integer B, which is the number of buttons for the lock. Output For each dataset, display the dataset number, a blank, the value B, a blank, and the number of valid sequences. Sample Input 3 3 4 3 Sample Output 1 3 25 2 4 149 3 3 25 Source |
[Submit] [Go Back] [Status] [Discuss]
设S(p,k)是斯特林数
S(p,k)的一个组合学解释是:将p个物体划分成k个非空的不可辨别的(可以理解为盒子没有编号)集合的方法数。
S(p,k)的递推公式是:
S(p,k) = k*S(p-1,k) + S(p-1,k-1) ,1<= k <=p-1
边界条件:
S(p,p) = 1 ,p>=0
S(p,0) = 0 ,p>=1
递推关系的说明:考虑第p个物品,p可以单独构成一个非空集合,此时前p-1个物品构成k-1个非空的不可辨别的集合,方法数为S(p-1,k-1);也可以前p-1种物品构成k个非空的不可辨别的集合,第p个物品放入任意一个中,这样有k*S(p-1,k)种方法。
第一类斯特林数和第二类斯特林数有相同的初始条件,但递推关系不同。} ——引自百度百科
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll f[20][20],c[20][20],a[20];
int T,n[110],m;
inline void solve()
{
for(int i=1;i<=m;++i)
for(int j=0;j<=i;++j)
if(j==0||j==i) c[i][j]=1;
else c[i][j]=c[i-1][j]+c[i-1][j-1];
f[1][1]=1; f[1][0]=0;
for(int i=2;i<=m;++i)
for(int j=0;j<=i;++j)
if(!j) f[i][j]=0;
else
if(j==1) f[i][j]=1;
else f[i][j]=f[i-1][j]*j+f[i-1][j-1];
a[1]=1;
for(int i=2;i<=m;++i) a[i]=a[i-1]*i;
return;
}
int main()
{
int i,j;
scanf("%d",&T);
for(i=1;i<=T;++i) scanf("%d",&n[i]),m=max(m,n[i]);
solve();
for(int l=1;l<=T;++l)
{
ll ans=0;
for(i=1;i<=n[l];++i)
for(j=1;j<=i;++j)
ans+=c[n[l]][i]*f[i][j]*a[j];
printf("%d %d %lld\n",l,n[l],ans);
}
return 0;
}
附ZYF神奇的思路:
f[i][j]表示将i个不同的小球放到j个不同的盒子的方案数。
f[i][j]=f[i-1][j]*j+f[i-1][j-1]*(j+1) f[i-1][j]*j表示把第i个小球放到已经分好的j个盒子中的任意一个中;f[i-1][j-1]*(j+1)表示第i个小球单独放在一个盒子中,这个盒子有(j+1)个不同的位置可以插入。
统计答案的时候ans+=f[i][j]*c(i,n)