【NOIP模拟】T2 管道(状压dp求图的dfs序方案数)
f[i][j]: i表示整个图走没走过的状态 j表示当前到了第j个点 存的值就是在这种情形下 可以走到的地方的状态
dp[i][j]:i表示整个图走没走过的状态 j表示当前在j点 访问剩余能去到的点的方案数
因此只需要跑一遍DFS就好了
#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define N 19
#define M 400
using namespace std;
int n,m,first[N],tot;
int f[1<<N][N],dp[1<<N][N];
struct node
{
int to,next;
}edge[2*M];
inline void addedge(int x,int y)
{
tot++;
edge[tot].to=y;
edge[tot].next=first[x];
first[x]=tot;
}
int dfs1(int sta,int now)
{
if(f[sta][now]) return f[sta][now];
f[sta][now]=sta; //sta一定是f[sta][now]的子集
for(int u=first[now];u;u=edge[u].next)
{
int vis=edge[u].to;
if(!(sta&(1<<vis))) //这个点没有走过
{
f[sta][now]|=dfs1(sta|(1<<vis),vis); //要"并"进去
}
}
return f[sta][now];
}
int dfs2(int sta,int now)
{
if(f[sta][now]==sta) return 1;
if(dp[sta][now]!=-1) return dp[sta][now];
dp[sta][now]=0;
for(int u=first[now];u;u=edge[u].next)
{
int vis=edge[u].to;
if(sta&(1<<vis)) continue;
int x=dfs2(sta|(1<<vis),vis);
int y=dfs2(f[sta|(1<<vis)][vis],now);
dp[sta][now]+=x*y%mod;
}
return dp[sta][now]%=mod;
}
main()
{
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
x--;
y--;
addedge(x,y);
addedge(y,x);
}
for(int i=0;i<(1<<n);i++)
{
for(int j=0;j<n;j++)
{
if(i&(1<<j))
{
f[i][j]=dfs1(i,j);
}
}
}
memset(dp,-1,sizeof(dp));
int ans=0;
for(int i=0;i<n;i++)
{
ans=(ans+dfs2(1<<i,i))%mod;
}
cout<<ans%mod;
return 0;
}
QQ40523591~欢迎一起学习交流~