首页 > 试题广场 >

发邮件

[编程题]发邮件
  • 热度指数:4541 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
NowCoder每天要给很多人发邮件。有一天他发现发错了邮件,把发给A的邮件发给了B,把发给B的邮件发给了A。于是他就思考,要给n个人发邮件,在每个人仅收到1封邮件的情况下,有多少种情况是所有人都收到了错误的邮件?
即没有人收到属于自己的邮件。

输入描述:
输入包含多组数据,每组数据包含一个正整数n(2≤n≤20)。


输出描述:
对应每一组数据,输出一个正整数,表示无人收到自己邮件的种数。
示例1

输入

2<br/>3

输出

1<br/>2
推荐
错排问题。

当n个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用D(n)表示,那么D(n-1)就表示n-1个编号元素放在n-1个编号位置,各不对应的方法数,其它类推.
第一步,把第n个元素放在一个位置,比如位置k,一共有n-1种方法;
第二步,放编号为k的元素,这时有两种情况:⑴把它放到位置n,那么,对于剩下的n-1个元素,由于第k个元素放到了位置n,剩下n-2个元素就有D(n-2)种方法;⑵第k个元素不把它放到位置n,这时,对于这n-1个元素,有D(n-1)种方法;
综上得到
D(n) = (n-1) [D(n-2) + D(n-1)]
特殊地,D(1) = 0, D(2) = 1.

有了递推公式,一切就迎刃而解了。
#include<stdio.h>
int main (void)
{
    long long der[ 21 ] = { 0, 0, 1 };
    int i;
    for ( i = 3; i < 21; i++ ){
        der[ i ] = ( i - 1 ) * ( der[ i - 2] + der[ i - 1 ] );
    }
   
    int n;
    while ( scanf( "%d", &n ) != EOF ){
        printf("%lld\n", der[ n ] );
    }
    return 0;
}



编辑于 2016-08-23 18:42:02 回复(9)
import java.util.*;

public class Main {
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        long[] a = new long[22];
        a[2] = 1;
        a[3] = 2;
        for (int i = 4; i < 22; i++){
            a[i] = (i-1)*(a[i-1]+a[i-2]);
        }
        while (scan.hasNext()){
            int n = scan.nextInt();
            System.out.println(a[n]);
        }
    }
}

发表于 2021-07-28 21:14:49 回复(0)
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while (sc.hasNext()) {
			int n = sc.nextInt();
			System.out.println(count(n));
		}
	}
	/**
	 * 错排算法,注意是long型
	 * @param n
	 * @return
	 */
	public static long count(int n) {
		if (n == 1) {
			return 0;
		} else if (n == 2) {
			return 1;
		} else {
			return (n - 1) * (count(n - 1) + count(n - 2));
		}

	}
}

编辑于 2016-08-27 15:53:35 回复(0)