管道 - dp - 状压

题目大意:给你一张无向图求合法的dfs序数量。dfs序不能在还可以dfs的时候退出。 n 18 n\le18
题解:
设dp(S,x)表示,已经遍历了S(包括x),现在在x,然后接下来要从x出发遍历一个极大的集合的方案数(注意不是全集)。
首先如果不存在y使得 g ( x , y ) = 1 g(x,y)=1 { y } S \{y\}\notin S ,那么dp(S,x)=1并退出。
否则只要进入了y,就会遍历一个确定的点集并回到x,设这个点集是T,那么
d p ( S T , x ) d p ( S , x ) d p ( S { y } , y ) dp(S|T,x)\leftarrow dp(S,x)dp(S|\{y\},y)
T可以dfs求出。

#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<b;i++)
#define lint long long
#define mod 998244353
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
#define con(x,i) (((x)>>(i))&1)
#define lb(x) ((x)&-(x))
const int N=20,MXS=(1<<18)+10;int n,g[N][N],gs[N][MXS];lint dp[MXS][N];bool calc[MXS][N];
int dfs(int x,int s,int &v) { v|=(1<<x);rep(y,0,n) if(g[x][y]&&!con(s|v,y)) dfs(y,s,v);return 0; }
inline int go(int x,int s) { return ((!gs[x][s])?dfs(x,s,gs[x][s]):0),gs[x][s]; }
int main()
{
//  freopen("data.in","r",stdin);
    n=inn();int m=inn(),x,y,U=(1<<n)-1;lint ans=0;
    rep(i,0,m) x=inn()-1,y=inn()-1,g[x][y]=g[y][x]=1;
    for(int s=U;s>=0;s--) rep(x,0,n) if(con(s,x))
    {
        int v=1;
        rep(y,0,n) if(g[x][y]&&!con(s,y))
            dp[s][x]+=dp[s|go(y,s)][x]*dp[s|(1<<y)][y],v=0;
        dp[s][x]+=v;
    }
    rep(x,0,n) ans+=dp[1<<x][x];return !printf("%lld\n",ans%mod);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/83747323