loj6094 归乡迷途

Posted Scx117

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了loj6094 归乡迷途相关的知识,希望对你有一定的参考价值。

题意:有一张n个点的无向图,点有标号。求满足下列性质的图有多少个。

1.任意节点到1的最短路唯一。2.i的最短路长度<=i+1的最短路长度。3.所有点的度数给定,为2或3。

n<=400.

 

标程:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int mod=1e9+7;
 4 const int inv2=5e8+4;
 5 typedef long long ll;
 6 const int N=405;
 7 int n,jc[N],inv[N],sum2[N],sum3[N],d,g[N][N][N],f[N][N],ans;
 8 void up(int &x,int y){x=((ll)x+y)%mod;}
 9 int c(int x,int y){return (ll)jc[x]*inv[y]%mod*inv[x-y]%mod;}
10 int main()
11 {
12     scanf("%d",&n);
13     for (int i=1;i<=n;i++) 
14     {
15        scanf("%d",&d);sum2[i]=sum2[i-1];sum3[i]=sum3[i-1];
16        (d==2)?sum2[i]++:sum3[i]++;    
17        if (i==1) f[d+1][d]=1;
18     }
19     jc[0]=jc[1]=inv[0]=inv[1]=1;
20     for (int i=2;i<=n;i++) jc[i]=(ll)jc[i-1]*i%mod,inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
21     for (int i=2;i<=n;i++) inv[i]=(ll)inv[i-1]*inv[i]%mod;
22     g[0][0][0]=1;
23     for (int i=3;i<=n;i++) 
24       for (int j=3;j<=i;j++)
25         up(g[0][0][i],(ll)g[0][0][i-j]*c(i-1,j-1)%mod*jc[j-1]%mod*inv2%mod);
26     for (int i=2;i<=n;i+=2)
27       up(g[0][i][0],(ll)(i-1)*g[0][i-2][0]%mod);
28     for (int j=1;j<=n;j++)
29       for (int k=1;k<=n-j;k++)
30       {
31           if (j>=2) up(g[0][j][k],(ll)(j-1)*g[0][j-2][k]%mod);
32           if (k) up(g[0][j][k],(ll)k*g[0][j][k-1]%mod);
33       }
34     for (int i=1;i<=n;i++)
35       for (int j=0;j<=n-i;j++)
36         for (int k=0;k<=n-i-j;k++)
37         {
38           if (j) up(g[i][j][k],(ll)j*g[i-1][j-1][k]%mod);
39           if (k) up(g[i][j][k],(ll)k*g[i-1][j+1][k-1]%mod);    
40         }
41     for (int i=3;i<=n;i++)//考虑前i个点 
42     {
43        for (int j=1;j<i-1;j++)//j个一层 
44          for (int k=1;k<i-j;k++)//上一层k个 
45               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);
46     }
47     for (int i=1;i<n;i++)
48       up(ans,(ll)f[n][i]*g[0][sum2[n]-sum2[n-i]][sum3[n]-sum3[n-i]]%mod);
49     printf("%d\n",ans);      
50     return 0;
51 }

 

易错点: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)。

以上是关于loj6094 归乡迷途的主要内容,如果未能解决你的问题,请参考以下文章

Python描述 LeetCode 6094. 公司命名

HDU6094 Rikka with K-Match

迷途指针

TCP迷途

迷途の荣耀 Sequence

迷途未远,来者可追