n个人排名,允许并列名次,共有多少种排名结果?
经典问题了,可以考虑递推:
假设n个人,排出了m个名次,有f(n,m)种结果(1<=m<=n)
当m=1
f(n,m)=1
当n<m
f(n,m)=0
当1<m<=n
假设n-1个人,排出了m个名次;新来1人,与前面某名次并列,有f(n-1,m)*m种结果
假设n-1个人,排出了m个名次;新来1人,与前面名次都不并列,有f(n-1,m-1)*m种结果
f(n,m)= f(n-1,m)*m + f(n-1,m-1)*m
综合上述,递推式:
0 n<m||m<1
f(n,m) = 1 1=m<=n
(f(n-1,m) + f(n-1,m-1))*m 1<m<=n
n个人的排名就是f(n,1)+f(n,2)+f(n,3)+...+f(n,n)
假设n个人,排出了m个名次,有f(n,m)种结果(1<=m<=n)
当m=1
f(n,m)=1
当n<m
f(n,m)=0
当1<m<=n
假设n-1个人,排出了m个名次;新来1人,与前面某名次并列,有f(n-1,m)*m种结果
假设n-1个人,排出了m个名次;新来1人,与前面名次都不并列,有f(n-1,m-1)*m种结果
f(n,m)= f(n-1,m)*m + f(n-1,m-1)*m
综合上述,递推式:
0 n<m||m<1
f(n,m) = 1 1=m<=n
(f(n-1,m) + f(n-1,m-1))*m 1<m<=n
n个人的排名就是f(n,1)+f(n,2)+f(n,3)+...+f(n,n)
作者:王希
链接:https://www.zhihu.com/question/30200444/answer/47183882
来源:知乎
第二条是全部并列,显然只有1种;
第三条是状态转移方程:当 个人排完名次之后加入一个人,有两种情况:
而答案就是 对 求和。写个程序算一下前几项:
链接:https://www.zhihu.com/question/30200444/answer/47183882
来源:知乎
一、直接动态规划
我们用表示有个人,种名次。那么显然有如下关系成立:
第二条是全部并列,显然只有1种;
第三条是状态转移方程:当 个人排完名次之后加入一个人,有两种情况:
- 他和某一个或几个人并列,这种情况下之前就已经有个排名了,他可能和这种中的任何一种并列;
- 他有一个新的名词,这种情况相当于他在个空档中选择一个,有种可能。
而答案就是 对 求和。写个程序算一下前几项:
#include <stdio.h>
#define A 15
typedef long long LL;
LL dp[A][A],ans[A],fact[A];
void fac()
{
for(int i = 1;i < A;i++) fact[i] = (i==1?1:(fact[i-1]*i));
}
void solve()
{
for(int i = 1;i < A;i++) ans[i] = 0;
for(int i = 1;i < A;i++)
for(int j = i;j < A;j++)
{
if(i==j) dp[i][j] = fact[i];
else if(i==1) dp[i][j] = 1;
else dp[i][j] = i*dp[i][j-1] + i*dp[i-1][j-1];
}
for(int i = 1;i < A;i++)
for(int j = 1;j <= i;j++)
ans[i] += dp[j][i];
}
int main()
{
fac();
solve();
for(int i = 1;i < A;i++) printf("f[%d] = %lld\n",i,ans[i]);
return 0;
}