您的位置:首页 > 其它

n个人排名,允许并列名次,共有多少种排名结果?

2017-09-22 21:24 393 查看


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            
4000
                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种;

第三条是状态转移方程:当

个人排完名次之后加入一个人,有两种情况:
他和某一个或几个人并列,这种情况下之前就已经有

个排名了,他可能和这

种中的任何一种并列;

他有一个新的名词,这种情况相当于他在

个空档中选择一个,有

种可能。

而答案就是



求和。写个程序算一下前几项:

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐