题意简述:有一张
n
个点,
n≤10
考虑状压dp,一个无环图一定是可以唯一分层的,将一开始入度为
0
的点放第一层,将这些点去掉,剩下出现的新的入度为
最近转C++,看起来神清气爽
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=100,P=1000000007;
int x[N],y[N],trans[10000],a[N],n,m;
ll f[1050][1050],m2[N];
int main(){
freopen("obelisk.in","r",stdin);
freopen("obelisk.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i = 1;i <= m;i++)
scanf("%d%d",&x[i],&y[i]);
memset(trans,0,sizeof(trans));
for (int i = 0;i <= n;i++)
trans[1 << i] = i + 1;
m2[0] = 1;
for (int i = 1;i <= m;i++)
m2[i] = m2[i - 1] * 2 % P;
int all = (1 << n) - 1,left;
memset(f,0,sizeof(f));
for (int i = 1;i <= all;i++)
f[i][i] = 1;
for (int i = 1;i <= all;i++)//picked
for (int j = i;j > 0;j = (j - 1) & i){//last row
left = all - i;
for (int k = left;k > 0;k = (k - 1) & left){//new pick
memset(a,0,sizeof(a));
for (int l = 1;l <= m;l++)//every edge to which point
if ((k & (1 << (y[l] - 1))) > 0){//to new point
if ((j & (1 << (x[l] - 1))) > 0)//from last row
a[trans[k & (1 << (y[l] - 1))]]++;
else
if ((i & (1 << (x[l] - 1))) > 0)//must from point we have
a[0]++;
}
ll base = 1;
for (int l = 1;l <= n;l++){
if ((k & (1 << (l - 1))) > 0)//new point
base = base * (m2[a[l]] - 1) % P;//must pick one
}
base = base * m2[a[0]] % P;
f[i | k][k] = (f[i | k][k] + f[i][j] * base) % P;
}
}
ll ans = 0;
for (int i = 1;i <= all;i++)
ans = (ans + f[all][i]) % P;
printf("%lld\n",ans);
}