【51nod】环

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Coldfresh/article/details/82353664

基准时间限制:1 秒 空间限制:131072 KB 分值: 80
有一个有向图。这张图有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

数据量这么小,有点转态压缩的意思。
我们来考虑一下环,很显然知道一个全排列就对应一环的种类。这个知识就是置换群的一个简单性质。
那么本质上问题就转化为有多少种不同的全排列。
d p [ i ] [ s ] 为考虑了前i个点,他们所对应的点集合是S,谁对应谁不清楚,但是我知道他们的集合。

发现超内存了,发现s集合大小和i大小是一样的,所以可以把第一维省去。
代码:

#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#define maxn 22
#define ll long long
#define mod 998244353
#define INF 0x3f3f3f3f
using namespace std;
bool g[25][25];
int dp[1<<maxn];
int get(int s)
{
    int ans=0;
    while(s)
    {
        ans++;
        s-=s&-s;
    }
    return ans;
}

int main()
{
    int n,m;
    int x,y;
    cin>>n>>m;
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d",&x,&y);
        g[x][y]=1;
    }
    dp[0]=1;
    for(int i=1;i<=n;++i)
    {
        for(int s=0;s<(1<<n);++s)
        {
            if(get(s)==i)
            {
                for(int j=1;j<=n;++j)
                {
                    if(g[i][j]&&(s&(1<<(j-1))))
                    {
                        dp[s]+=dp[s^(1<<(j-1))];
                        if(dp[s]>=mod)dp[s]-=mod;
                    }
                }
            }
        }
    }
    cout<<dp[(1<<n)-1]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Coldfresh/article/details/82353664
今日推荐