zoukankan      html  css  js  c++  java
  • (算法)金钗赛诗

    题目:

    赛诗会后,十二金钗待奔前程。分别宴上,12人各写了一首诗放入包囊。

    大家随机取一个,若取到自己的诗,则再取一个,并放回自己的诗,12人都拿到诗算一种分配。

    请问:共有多少种不同的分配?

    思路:

    问题简化:给定n个人写n首诗,要求赠给其他人,共有多少种分配方法。

    通俗一点就是:1到n的全排列,第i个数不是i的排列共有多少种?

    其实这就是“错位排列”。

    (错位排列问题的答案可以由“错排公式”求得,关于错排公式的推导可以参考百度百科:http://baike.baidu.com/view/668994.htm)

    这里简单从类似动态规划的角度来分析问题:

    假设n个数的错位排列数目为dp[n]

    第n个数可以放置在1...(n-1)之间的任何一个位置,共(n-1)种方法;

    假设第n个数放在了第k个位置,那么对于数字k而言:

    • 要么放在第n个位置;
    • 要么不放在第n个位置;

    如果放在了第n个位置,那么相当于n和k做了交换,剩下的就是其他(n-2)个数的错位排列了,即dp[n-2];

    如果不放在第n个位置,那么剩余(n-1)个数(可以将此时k看出原来的n,即此时剩下除了k位置外的所有数),即dp[n-1];

    因此动态规划的状态转移方程为:

    dp[n]=(n-1)*(dp[n-1]+dp[n-2]);

    初始状态:

    当n=1;dp[1]=0;

    当n=2;dp[2]=1;(两个数,只存在一种错排的可能)

    通过上述公式的递推可以得到“错排公式”:

    D(n) = n! [1/0! - 1/1! + 1/2! - 1/3! + 1/4! + ... + (-1)^n/n!].

    代码:

    #include <iostream>
    
    using namespace std;
    
    int miscombination_1(int n){
        int A[n+1];
        A[1]=0;
        A[2]=1;
        for(int i=3;i<=n;i++)
            A[i]=(i-1)*(A[i-1]+A[i-2]);
        return A[n];
    }
    
    int miscombination_2(int n){
        if(n<=2)
            return n-1;
        int first=0;
        int second=1;
        int third=0;
        for(int i=3;i<=n;i++){
            third=(i-1)*(first+second);
            first=second;
            second=third;
        }
        return third;
    }
    
    int main()
    {
        cout << miscombination_1(12) << endl;
        cout << miscombination_2(12) << endl;
        return 0;
    }
    

    问题答案:

    176214841

  • 相关阅读:
    MSSQL经典语句
    注销时关闭当前窗体,返回登入界面
    自定义控件小结进阶篇
    精妙SQL语句大全
    触发器MSSQL常用操作
    经典SQL语句大全
    文件下载
    android Notification 的使用
    startActivityForResult()的用法
    Android手机中获取手机号码和运营商信息
  • 原文地址:https://www.cnblogs.com/AndyJee/p/4636075.html
Copyright © 2011-2022 走看看