不容易系列之一 - 九度教程第 94 题

不容易系列之一 - 九度教程第 94 题

题目

时间限制:1 秒 内存限制:128 兆 特殊判题:否
题目描述:
大家常常感慨,要做好一件事情真的不容易,确实,失败比成功容易多了!做好“一件”事情尚且不易,若想永远成功而总从不失败,那更是难上加难了,就像花钱总是比挣钱容易的道理一样。话虽这样说,我还是要告诉大家,要想失败到一定程度也是不容易的。比如,我高中的时候,就有一个神奇的女生,在英语
考试的时候,竟然把 40 个单项选择题全部做错了!大家都学过概率论,应该知道出现这种情况的概率,所以至今我都觉得这是一件神奇的事情。如果套用一句经典的评语,我们可以这样总结:一个人做错一道选择题并不难,难的是全部做错,一个不对。不幸的是,这种小概率事件又发生了,而且就在我们身边:
事情是这样的——HDU 有个网名叫做 8006 的男性同学,结交网友无数,最近该同学玩起了浪漫,同时给 n 个网友每人写了一封信,这都没什么,要命的是,他竟然把所有的信都装错了信封!注意了,是全部装错哟!现在的问题是:请大家帮可怜的 8006 同学计算一下,一共有多少种可能的错误方式呢?
输入:
输入数据包含多个多个测试实例,每个测试实例占用一行,每行包含一个正整数 n(1<n<=20),n 表示 8006 的网友的人数。
输出:
对于每行输入请输出可能的错误方式的数量,每个实例的输出占用一行。
样例输入:
2
3
样例输出:
1
2

在该题中容易得到规模较小时的错装方式数量。如 n 为 1 时,数量为 0;n 为 2 时数量为 1;n 为 3 时数量为 2。按照 n 的取值顺序将所有的错装方式数量排列为一个数列,同样用 F[n]表示数列里第 n 个数的取值,F[n]同时代表 n 个信封的错装方式总数,确定该数列的递推关系。

当 n 大于 3 时,考虑 n 封信全部装错的情况。将信封按顺序由 1 到 n 编号。在任意一种错装方案中,假设 n号信封里装的是 k 号信,而 n 号信则装在 m 号信封里(m号信封里装的是 n 号信)。按照 k 和 m 等值与否将总的错装方式分为两类。

若 k 不等于 m,交换 n 号信封和 m 号信封的信后,n 号信封里装的恰好是对应的信,而 m 号信封中错装 k 号信,即除 n 号信封外其余 n-1 个信封全部错装,其错装方式等于 F[n - 1],又由于 m 的 n-1 个可能取值,这类错装方式总数为(n - 1)* F[n - 1]。也可以理解为,在 n-1 个信封错装的 F[n - 1]种方式的基础上,将 n 号信封所装的信与 n - 1 个信封中任意一个信封(共有 n-1 中选择)所装的信做交换后,得到所有信封全部错装的方式数。

另一种情况,若 k 等于 m,交换 n 号信封和 m 号信封的信后,n 号信封和 m号信封里装的恰好是对应的信,这样除它们之外剩余的 n-2 个信封全部错装,其错装方式为 F[n - 2],又由于 m 的 n-1 个取值,这类错装方式总数为(n - 1)* F[n- 2]。也可以理解为,在 n - 2 个信封全部错装的基础上,交换最后两个信封中的信(n 号信封和 1 到 n-1 号信封中任意一个,共有 n-1 种选择),使所有的信封全部错装的方式数。

综上所述,F[n] = (n - 1) * F[n - 1] + (n - 1) * F[n - 2]。这就是有名的错排公式

#include <stdio.h>

long long F[21];//数值较大选用long long

int main()
{
    F[1]=0;
    F[2]=1;
    for(int i=3;i<=20;i++){
        F[i]=(i-1)*F[i-1]+(i-1)*F[i-2];
        //递推求得数列每一个数字
    }

    int n;
    while(scanf("%d",&n)!=EOF){
        printf("%lld\n",F[n]);//输出
    }

    return 0;
}

递推求解问题,根据输入的顺序,其答案往往排列成一个数列。为了求得数列中的每一个数字,我们首先得到输入规模较小时的答案,即数列开头的几个数字。分析问题,将每一个问题都分割成规模较小的几个问题,分割过程中要做到不遗漏不重复,并确定它们的关系从而得到递推关系式,利用它求出每一个输入所对应的答案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值