NOIP模拟题 管道

 题目大意

给定$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;
}
原文地址:https://www.cnblogs.com/OYJason/p/9908650.html