【NOIP2017模拟赛】二分图+状态压缩DP Graph(好题)

来源:互联网 发布:2017fc2破解版域名设置 编辑:程序博客网 时间:2024/06/05 06:52

这里写图片描述

题解

这道题其实是一个NP完全问题(23333),但是由于数据小啊,我们可以搞一搞。很容易发现,如果我们将一个点拆成两个点,一个代表出点,一个代表入点。当增加了一条有向边,就出点向入点连一条边(例如将u拆成u1u2v拆成v1v2,然后边u>v就变成边u1>v2),我们发现这样就变成了一个二分图(怎么可能两个出点或两个入点之间有一条边呢……),此时二分图的任意一个完备匹配,都是符合题意的环组。也就是说,我们只需要求二分图完备匹配的方案数即可。
此时我们考虑状态压缩DP,f[i][s]s为一个被压缩的状态)表示前i个出点匹配了状态为s的入点的方案数(前提是|s|=i),可以很容易得到状态转移方程,于是我们就做出来了……依然是没有注释的代码……将就能看就行……

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 25#define mod 998244353#define P 1048580int n,m,lg2[P],bit[P];bool A[N][N];int f[N][P];int getint(){    int p=0;    char c=getchar();    while(c<'0'||c>'9')c=getchar();    while(c>='0'&&c<='9')p=p*10+c-'0',c=getchar();    return p;}int main(){    n=getint();m=getint();    lg2[1]=1;bit[1]=1;    for(int i=2;i<=(1<<20);i++)    {        lg2[i]=lg2[i>>1]+1;        for(int j=0;j<=20;j++)            if(i&(1<<j))                bit[i]++;    }    for(int i=1;i<=m;i++)    {        int a=getint(),b=getint();        A[a][b]=1;    }    f[0][0]=1;    for(int i=1;i<=n;i++)    {        for(int j=1;j<(1<<n);j++)        {            if(bit[j]!=i)                continue;            for(int k=j;k;k-=k&-k)            {                int v=lg2[k&-k];                if(A[i][v])                    f[i][j]=(f[i][j]+f[i-1][j-(k&-k)])%mod;            }        }    }    printf("%d\n",f[n][(1<<n)-1]);}
阅读全文
0 0
原创粉丝点击