题目给出一个 n 个点,m 条边的有向图,要求求出删掉一些边以后,整个图强联通的方案数,其中 n≤15,m≤n(n−1)
好难啊qaq 题解传送门:portal
实现上也有一些技巧要注意qaq
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 20
#define mod 1000000007
inline char gc(){
static char buf[1<<16],*S,*T;
if(T==S){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,m,out[33000],in[33000],bin[220],bitcnt[33000],f[33000],g[33000],h[33000],w[33000];
//f[S]--点集为S的子图强连通的方案数
//g[S],点集为S的子图分成奇数个scc的方案数-分成偶数个scc的方案数 h[S],点集为S的导出子图的边数 w[S],T集合为S的点时U-T连向T的边数
inline void dec(int &x,int y){x-=y;if(x<0) x+=mod;}
inline void inc(int &x,int y){x+=y;if(x>=mod) x-=mod;}
int main(){
// freopen("a.in","r",stdin);
n=read();m=read();bin[0]=1;
for(int i=1;i<=m;++i) bin[i]=bin[i-1]<<1,bin[i]%=mod;
for(int S=1;S<bin[n];++S) bitcnt[S]=bitcnt[S^(S&-S)]+1;
while(m--){
int x=bin[read()-1],y=bin[read()-1];
out[x]|=y;in[y]|=x;
}for(int S=1;S<bin[n];++S){
int x=S&-S,t=S^x;//固定x在S^ss集合中
for(int ss=t;ss;ss=(ss-1)&t)
dec(g[S],(ll)f[S^ss]*g[ss]%mod);
h[S]=h[t]+bitcnt[out[x]&S]+bitcnt[in[x]&S];f[S]=bin[h[S]];
for(int ss=S;ss;ss=(ss-1)&S){//枚举T集合
int x=(S^ss)&-(S^ss);
if(ss!=S) w[ss]=w[ss|x]-bitcnt[in[x]&(S^ss)]+bitcnt[out[x]&ss];
else w[ss]=0;dec(f[S],(ll)bin[w[ss]+h[S^ss]]*g[ss]%mod);
}inc(g[S],f[S]);
}printf("%d\n",f[bin[n]-1]);
return 0;
}