【51Nod1833】环

来源:互联网 发布:交通银行软件开发待遇 编辑:程序博客网 时间:2024/06/07 06:03

有一个有向图。这张图有n个点和m条有向边。
他很好奇不相交的环(简单环)来覆盖所有点的方案数(数字可能很大请模998,244,353)。
Input
第一行有n和m。(1<=n<=20,1<=m<=n*(n-1))
后面m行描述着m条边。
输入保证没有重边自环。
Output
输出方案数。
Input示例
3 3
1 2
2 3
3 1
Output示例
1

题解
发现简单环就是二分图完美匹配的方案数,记f[i][j]表示前i个数,匹配了j状态的方案数。

代码

#include<bits/stdc++.h>typedef long long ll;const int inf=1000000007;const int mod=998244353;const double eps=0.00000001;using namespace std;inline int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}int n,m,f[22][(1<<20)+5];vector<int>l[25];int cal(int x){    int ans=0;    while (x) ans+=x&1,x>>=1;    return ans;}int main(){    n=read();m=read();    for (int i=1;i<=m;i++)    {        int u=read(),v=read();        l[u].push_back(v);    }    f[0][0]=1;    for (int i=1;i<=n;i++)        for (int j=1;j<(1<<n);j++)if (cal(j)==i)            for (int k=0;k<l[i].size();k++)            {                int x=l[i][k];                if (!(j&(1<<(x-1)))) continue;                (f[i][j]+=f[i-1][j^(1<<(x-1))])%=mod;            }    printf("%d",f[n][(1<<n)-1]);    return 0;}