题目大意
给定$n$个点的无向图,求它的$Dfs$序方案数
$nleq 18$
题解
状压$Dp+$记忆化搜索。
设$F_{i,now}$表示到达$i$其中$now$集合代表的点集已经遍历过,还需要遍历其余点的方案数。
考虑枚举$i$每一个不在点集内部的出边进行记忆化搜索转移。
这样会有一个问题:无法解决回溯。
考虑设$G_{i,now}$表示已选了点集$now$当前位置在$i$,能遍历到的所有最大状态,即当前情况下$i$的子树的集合与$now$的并集。
$G_{i,now}$也可以用记忆化搜索处理。
这样,对于每一个$F_{x,now}$,枚举每一个$ otin now$的$x$的后继$y$,
$$F_{x,now}=sum F_{x,G_{y,now|y}} imes F_{y,now|y}$$
复杂度$O(n^2 2^n)$
#include<bits/stdc++.h> #define debug(x) cerr<<#x<<" = "<<x #define sp <<" " #define el <<endl #define LL long long #define M 20 #define mod 998244353 using namespace std; int read(){ int nm=0,fh=1; char cw=getchar(); for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh; for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0'); return nm*fh; } int n,m,fs[M],sz[M],c[M][M],F[19][1<<19],G[19][1<<19],ans; #define upd(x,y) x+=y,x=(x>=mod?x-mod:x) int Trans(int x,int now){ if(G[x][now]>=0) return G[x][now]; G[x][now]=now; for(int k=1;k<=sz[x];k++){ int to=c[x][k]; if((now>>(to-1))&1) continue; G[x][now]|=Trans(to,now|(1<<(to-1))); }return G[x][now]; } int Dp(int x,int now){ if(Trans(x,now)==now) return 1; if(F[x][now]>=0) return F[x][now]; F[x][now]=0; for(int k=1;k<=sz[x];k++){ int to=c[x][k]; if((now>>(to-1))&1) continue; int t1=Dp(to,now|(1<<(to-1))); int t2=Dp(x,now|Trans(to,now|(1<<(to-1)))); int res=(LL)t1*(LL)t2%mod; upd(F[x][now],res); } return F[x][now]; } int main(){ n=read(),m=read(),memset(G,-1,sizeof(G)),memset(F,-1,sizeof(F)); for(int i=1;i<=m;i++){int x=read(),y=read();c[x][++sz[x]]=y,c[y][++sz[y]]=x;} for(int i=1;i<=n;i++) upd(ans,Dp(i,1<<(i-1))); printf("%d ",ans); return 0; }