版权声明:本文为博主原创文章,未经博主允许不得转载。 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
数据量这么小,有点转态压缩的意思。
我们来考虑一下环,很显然知道一个全排列就对应一环的种类。这个知识就是置换群的一个简单性质。
那么本质上问题就转化为有多少种不同的全排列。
设
为考虑了前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;
}