题意:有一张n个点的无向图,点有标号。求满足下列性质的图有多少个。
1.任意节点到1的最短路唯一。2.i的最短路长度<=i+1的最短路长度。3.所有点的度数给定,为2或3。
n<=400.
标程:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+;
const int inv2=5e8+;
typedef long long ll;
const int N=;
int n,jc[N],inv[N],sum2[N],sum3[N],d,g[N][N][N],f[N][N],ans;
void up(int &x,int y){x=((ll)x+y)%mod;}
int c(int x,int y){return (ll)jc[x]*inv[y]%mod*inv[x-y]%mod;}
int main()
{
scanf("%d",&n);
for (int i=;i<=n;i++)
{
scanf("%d",&d);sum2[i]=sum2[i-];sum3[i]=sum3[i-];
(d==)?sum2[i]++:sum3[i]++;
if (i==) f[d+][d]=;
}
jc[]=jc[]=inv[]=inv[]=;
for (int i=;i<=n;i++) jc[i]=(ll)jc[i-]*i%mod,inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
for (int i=;i<=n;i++) inv[i]=(ll)inv[i-]*inv[i]%mod;
g[][][]=;
for (int i=;i<=n;i++)
for (int j=;j<=i;j++)
up(g[][][i],(ll)g[][][i-j]*c(i-,j-)%mod*jc[j-]%mod*inv2%mod);
for (int i=;i<=n;i+=)
up(g[][i][],(ll)(i-)*g[][i-][]%mod);
for (int j=;j<=n;j++)
for (int k=;k<=n-j;k++)
{
if (j>=) up(g[][j][k],(ll)(j-)*g[][j-][k]%mod);
if (k) up(g[][j][k],(ll)k*g[][j][k-]%mod);
}
for (int i=;i<=n;i++)
for (int j=;j<=n-i;j++)
for (int k=;k<=n-i-j;k++)
{
if (j) up(g[i][j][k],(ll)j*g[i-][j-][k]%mod);
if (k) up(g[i][j][k],(ll)k*g[i-][j+][k-]%mod);
}
for (int i=;i<=n;i++)//考虑前i个点
{
for (int j=;j<i-;j++)//j个一层
for (int k=;k<i-j;k++)//上一层k个
up(f[i][j],(ll)f[i-j][k]*g[j][sum2[i-j]-sum2[i-j-k]][sum3[i-j]-sum3[i-j-k]]%mod);
}
for (int i=;i<n;i++)
up(ans,(ll)f[n][i]*g[][sum2[n]-sum2[n-i]][sum3[n]-sum3[n-i]]%mod);
printf("%d\n",ans);
return ;
}
易错点:1.注意f[][]的初始化,设第一个点的度数为d,f[d+1][d]=1。
2.当dp转移式较为复杂时,考虑辅助数组来降低复杂度。
题解:dp
建立最短路树,发现同一层点的编号连续(因此可以区间dp)。由“最短路唯一”的性质可以得到,非树边一定是同层之间互连。
对于某一层的点,剩下度为1和2的点各有多少个可以互连要根据下一层有多少个儿子决定。
f[i][j]表示前i个点,j个点在当前的最后一层,最后一层没有互连的方案数。g[i][j][k]表示这一层有i个点,上一层有j个剩下度为1的点,k个剩下度为2的点。
显然f[i][j]=sigma(f[i-j][k]*g[j][k1][k2])。统计答案的时候就累加f[n][i]*g[0][k1][k2]即可。
预处理g:1.考虑如果只存在>=3个剩下度为2的点,那么必然构成环:枚举第k个元素所在的环,g[0][0][k]=sigma(g[0][0][k-l]*C(k-1,l-1)*(l-1)!/2);(最后一项是圆排列去重)
2.如果只存在剩下度为1的点,那么一定是两两连边:g[0][j][0]=(j-1)*g[0][j-2][0]。j一定是偶数。
3.如果度为1和2的点都有,而且没有下一层:任意选取一个度为1的点,它与度为1的点或度为2的点连边:g[0][j][k]=(j-1)*g[0][j-2][k]+k*g[0][j][k-1].(连度为1的,少了2个度为1的点;连度为2的点,少了一个度为2的点,度为1的点+1-1不变)
4.普遍情况:任意选取i个点中的一个,考虑和度为1的连边还是和度为2的点连边:g[i][j][k]=j*g[i-1][j-1][k]+k*g[i-1][j+1][k-1].
时间复杂度O(n^3)。