题解:
区间
dp
d
p
f[i][j]
f
[
i
]
[
j
]
表示
i
i
到有边且构成树的方案数
g[i][j]
g
[
i
]
[
j
]
表示
i
i
到无边且构成树的方案数
转移:枚举
i,j
i
,
j
左右端点,
k
k
是断点
g[i][j]+=∑j−1k=i+1f[k][j]∗(f[i][k]+g[i][k])
g
[
i
]
[
j
]
+
=
∑
k
=
i
+
1
j
−
1
f
[
k
]
[
j
]
∗
(
f
[
i
]
[
k
]
+
g
[
i
]
[
k
]
)
初始化只要
f[i][j]=1
f
[
i
]
[
j
]
=
1
就可以了
Code:
C
o
d
e
:
#include <cstdio>
#define ll long long
using namespace std;
const int N=1005,mod=1e9+7;
int n;
ll a[N][N],f[N][N],g[N][N];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)f[i][i]=1;
for(int len=2;len<=n;len++)
for(int i=1;i+len-1<=n;i++)
{
int j=i+len-1;
for(int k=i;k<j;k++)
if(a[i][j])
f[i][j]=(f[i][j]+(f[i][k]+g[i][k])*(f[k+1][j]+g[k+1][j])%mod)%mod;
for(int k=i+1;k<j;k++)
if(a[k][j])
g[i][j]=(g[i][j]+f[k][j]*(f[i][k]+g[i][k])%mod)%mod;
}
printf("%lld\n",(f[1][n]+g[1][n])%mod);
return 0;
}