O - Matching 题解(状压dp)

题目链接

题目大意

给你一个方形矩阵mp,边长为n(n<=21)

有n个男生和女生,如果\(mp[i][j]=1\) 代表第i个男生可以和第j个女生配对

问有多少种两两配对的方式,使得所有男生和女生都一一匹配

题目思路

看数据显然是一个状压dp

\(dp[i][j]\)表示前i个男生匹配的女生的状态为j,三重for即可

优化:但是枚举状态的时候其实判断有多少个1就已经知道有多少个人被匹配了,那么其实枚举人数是没有必要的,可以先枚举状态然后判断人数即可优化一维循环,当然数组也可以滚动优化代码懒得写了

代码

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
#define debug printf(" I am here\n");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=20+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-10;
int n;
int mp[maxn][maxn];
ll dp[maxn][1<<21];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&mp[i][j]);
        }
    }
    dp[0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int now=1<<(j-1);
            if(!mp[i][j]) continue;
            for(int pre=0;pre<=(1<<n)-1;pre++){
                if(dp[i-1][pre]&&(now&pre)==0){
                    dp[i][pre|now]+=dp[i-1][pre];
                    dp[i][pre|now]%=mod;
                }
            }
        }
    }
    printf("%lld\n",dp[n][(1<<n)-1]);
    return 0;
}

posted @ 2020-11-22 17:15  hunxuewangzi  阅读(240)  评论(0)    收藏  举报