这道题一开始自己没想到用动态规划去做,后面看了下大佬们的解法,才发现原来还可以动态规划去做。
首先讲下我这种解法吧:
1.这是概率论中一道典型的配对模型
所谓配对模型就是,比如n个人任取n顶不同的帽子,n把钥匙随机开n把锁,求至少有一对配对成功的几率。
对应这种配对问题,存在着一个公式,
全部配对错误的可能性为:
1/2!-1/3!-...+(-1)^(n-1)*1/n!
利用这个公式我们便可以对问题进行求解

#include<bits/stdc++.h>
using namespace std;
void Help(int n)
{
    double a=1;
    double b=2;
    double i=2;
    double sum=0;
    while(i<=n)
    {
        sum+=a*(1/b);
        b*=i+1;
        a=-a;
        i++; 
    }
    sum*=100;
    cout<<setiosflags(ios::fixed)<<setprecision(2)<<sum<<"%"<<endl;

}

int main()
{
    int m;
    while(cin>>m)
    {
        Help(m);
    }
}

对于第二种解法而言:
假设a的名字没有被a拿到,其他n - 1个人都有可能拿到,即有n - 1种情况。假设b拿到了a的名字,那么对于b的名字有两种情况, 第一种是b的名字被a拿到了,也就是a、b互相拿到了对方的名字,那么对于其他n - 2个人互相拿错又是一个子问题f(n - 2). 第二种是b的名字没有被a拿到,则剩下的问题是子问题f(n - 1).因此可得递推公式f(n) = (n - 1) * (f(n - 1) + f(n - 2)). 最终得出公式n人都不获奖的概率h(n) = (n - 1) * (f(n - 1) + f(n - 2)) / (n!)

#include<bits/stdc++.h>
using namespace std;
long long  dp[1007];
double Help(int m)
{
    if(dp[m]!=0) return dp[m];
    else return dp[m]=(m-1)*(Help(m-1)+Help(m-2));
}
int main()
{
    int m;
    memset(dp,0,sizeof(dp));
    dp[1]=0;
    dp[2]=1;
    dp[3]=2;
    while(cin>>m)
    {
        double g=Help(m);
        for(int i=1;i<=m;i++)
        {
            g=g/i;
        }
        g*=100;
        cout<<setiosflags(ios::fixed)<<setprecision(2)<<g<<"%"<<endl;
    }
}