​Lisa​

显然状态压缩

然后,对于一个点集S,我们很容易求出这个点集可以形成的任意图\(F_S\)

这个很容易预处理出来

然后呢,对于这个直接求联通的方案书并不容易,但是,可以用总方案减去不连通的方案数。

不连通的方案视为两个点集,一个点集随便,另一个点集必须联通。

所以在预处理完了以后,我们首先要做的就是在当前集合里剥出一个点作为强制的联通集合的点,然后枚举这个集合剥离后的子集作为随意点,其子集的补集作为联通点集。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
int n;
int ma[101][101];
int maxn=18;
int f[1<<18];
int dp[1<<18];
int g[1<<18];
int m=1000000007;
int cnt;
signed main(){
scanf("%d",&n);
cnt=(1<<n)-1;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
scanf("%d",&ma[i][j]);
}
}
for(int k=0;k<=cnt;++k){
f[k]=1;
for(int i=1;i<=n;++i){
if(k&1<<i-1){
for(int j=i+1;j<=n;++j){
if(k&1<<j-1){
f[k]=f[k]*(ma[i][j]+1)%m;
f[k]%=m;
}
}
}
}
}
for(int k=1;k<=cnt;++k){
dp[k]=f[k];
int frm=k^(k&-k);
for(int i=frm;i;i=(i-1)&frm){
dp[k]=(dp[k]-f[i]*dp[i^k]%m+m)%m;
}
}
cout<<dp[cnt];
return 0;
}