b_vj_Permutation(反向思维算出不完美的排列个数)

求出数字1...n的全排列中完美排列的个数,完美排列是指排列的第(a_i)位为数字(b_i)(0<=i<m)

思路:f[i][j]表示排列长度为i时,数字填充状态为j时的不完美排列数

#include<cstdio>
#include<cstring>
#include<iostream>
typedef long long ll;
using namespace std;
const int N=17;
ll n,m,tot,p[N][N],f[N][1<<N],fac[N]; 
void init() {
    fac[0]=1; for (int i=1;i<=N;i++) fac[i]=fac[i-1]*i;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int Q; cin>>Q, init();
    for (int q=0; q<Q; q++) {
        cin>>n>>m, tot=1<<n, memset(p,0,sizeof p), memset(f,0,sizeof f);
        for (int i=0; i<m; i++) {
            int a,b; cin>>a>>b;
            p[a-1][b-1]=1;
        }
        for (int i=0; i<n; i++) if (!p[0][i]) f[0][1<<i]=1;
        for (int i=1; i<n; i++)
        for (int j=0; j<tot; j++)
        for (int k=0; k<n; k++) if ((j&(1<<k))==0 && !p[i][k]) //k是当前要填的数字,数字的第i位能填k(状态j没有填过k),且k不是"完美数字"是才是不完美
            f[i][j|1<<k]+=f[i-1][j]; 
        }
        printf("Case %d: %lld
", q+1, fac[n]-f[n-1][tot-1]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wdt1/p/13941772.html