杭電OJ 2048 完全錯排的可能性

paopaotangzu發表於2024-03-11

神、上帝以及老天爺

/*
人數從1到4寫手動模擬找出遞推規律:
總體上就是得出n的完全錯排方案個數, 然後除以n!即可;關鍵是求n的完全錯排方案個數;
第n個人可以選取前n-1個人中任意一個人的字條,第n個人有n-1種選擇,假設第n個人取到的是第i個人的字條,
1.這時i可以保留第n個人的字條,剩餘的n-2個人完全錯排;(要遞推就要找是否出現有n-1或n-2完全錯排的情況),(i可以保留第n個人的字條的時候滿足)(則還要討論另一種情況若第i個人未保留第n個人的字條)
2.若第i個人未保留第n個人的字條,則相當於除第n個人之外的剩餘n-1個人完全錯排(因為第i個人不能保留第n個人的紙條)(第2種情況也聯絡到遞推式,相當於!)
第二種情況以紙條ABCDE為例,
A選了紙條B,B未選紙條A,則還剩下紙條ACDE,人BCDE,因為此時B不能選紙條A,在完全錯排中人B就相當於人A的作用了(錯排人A不能選紙條A),
則紙條ACDE,人BCDE相當於人ACDE與紙條ACDE完全錯排
遞推公式為:a[n] = (n-1)*(a[n-1] + a[n-2]);
*/

本題考察遞推法,就要手動模擬總結出遞推的公式。其中,\(n!\)是指全排列的所有排列個數。

神、上帝以及老天爺
#include <iostream>
#include <cstdio>

using namespace std;

const int MAXN = 20 + 5;
long long situation[MAXN];

void Initial()
{
    situation[1] = 0;
    situation[2] = 1;
    for(int i = 3; i < MAXN; ++i) { //第n個人有n-1種選擇
        situation[i] = (i - 1) * (situation[i - 1] + situation[i - 2]);
    }
}
//20的階乘可能超過int範圍
long long JieMutipe(int x) {
    long long ans = 1;
    for(int i = 2; i <= x; ++i) {
        ans *= i;
    }
    return ans;
}

int main()
{
    Initial();
    int c, n;
    cin >> c;
    while(c--) {
        cin >> n;
        double answer = (double) situation[n] / JieMutipe(n) * 100;
        printf("%.2f%%\n", answer);
    }
    return 0;
}

要注意用long long儲存資料,否則可能越界

參考資料:
杭電OJ2048

相關文章