• CSU 1805 Three Capitals(矩阵树定理+Best定理)


    http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1805

    题意:

    A和B之间有a条边,A和G之间有b条边,B和G之间有c条边。现在从A点出发走遍所有的边,然后再回到A点,问一共有多少种方法。

    思路:

    16年湖南省赛题目,这道题目是求欧拉回路的个数,和生成树的计数有一定的联系。

    首先给出神奇的Best定理,这是什么鬼定理,反正查不到什么有关该定理的文章。。。

    $ec(G)=t_s(G)cdot deg(s)! cdot prod_{vin V, v e s} (deg(v)-1)!, t_s(G):=$以s为根的外向树的个数。

    这个有向图的外向树个数其实和无向图的生成树个数是差不多的,总之就是矩阵树定理,但是稍微还是有点不同的地方。

    基尔霍夫矩阵的构造是不太一样的,毕竟一个是无向图,一个是有向图:

    无向图中的度数矩阵是每个顶点的度数,有向图中的度数矩阵是每个顶点的入度。

    邻接矩阵的话是u->v的边数,这和无向图是差不多的。

    然后是矩阵的计算:

    无向图的生成树个数=任意n-1阶主子式的值

    有向图的外向树个数=除去根节点所在的阶的主子式的值

    注意一下,这道题目还需要计算组合数,比如说,A和B之间有a条边,那么我可以选择x条边为入边,那么剩余的a-x条边为出边,在这个过程中就会有不同的选择方法。总的也就是$C(a,x)*C(b,y)*C(c,z)$。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<sstream>
     6 #include<vector>
     7 #include<stack>
     8 #include<queue>
     9 #include<cmath>
    10 #include<map>
    11 #include<set>
    12 using namespace std;
    13 typedef long long ll;
    14 typedef pair<int,ll> pll;
    15 const int INF = 0x3f3f3f3f;
    16 const int maxn=500+5;
    17 const ll mod=1e9+7;
    18 
    19 int a,b,c;
    20 ll f[100005];
    21 ll A[5][5];
    22 
    23 void init()
    24 {
    25     f[0]=1;
    26     for(int i=1;i<=100005;i++)  f[i]=f[i-1]*i%mod;
    27 }
    28 
    29 ll qpow(ll a,ll n)
    30 {
    31     ll ans=1;
    32     while(n)
    33     {
    34         if(n&1) ans=ans*a%mod;
    35         a=a*a%mod;
    36         n>>=1;
    37     }
    38     return ans;
    39 }
    40 
    41 ll C(ll n,ll m)
    42 {
    43     return (f[n]*qpow(f[m],mod-2)%mod)*qpow(f[n-m],mod-2)%mod;
    44 }
    45 
    46 ll calc()
    47 {
    48     return (A[1][1]*A[2][2]%mod-A[1][2]*A[2][1]%mod+mod)%mod;
    49 }
    50 
    51 int main()
    52 {
    53     //freopen("in.txt","r",stdin);
    54     init();
    55     while(~scanf("%d%d%d",&a,&b,&c))
    56     {
    57         if((a+c)&1 || (a+b)&1 || (b+c)&1)  {puts("0");continue;}
    58         ll ans=0;
    59         for(int i=0;i<=a;i++)  //枚举A->B的边数
    60         {
    61             memset(A,0,sizeof(A));
    62             A[0][0]=(a+b)/2;
    63             A[1][1]=(a+c)/2;
    64             A[2][2]=(b+c)/2;
    65             A[0][1]=-i;
    66             A[1][0]=-(a-i);
    67             A[0][2]=-(A[0][0]-i);
    68             A[2][0]=-(b+A[0][2]);
    69             A[1][2]=-(A[1][1]+A[1][0]);
    70             A[2][1]=-(c+A[1][2]);
    71             if(A[0][2]>0 || A[2][0]>0 || A[1][2]>0 || A[2][1]>0)  continue;
    72 
    73             ll res=(C(a,i)*C(c,-A[1][2])%mod)*C(b,-A[0][2])%mod;
    74 
    75             res=(res*calc())%mod;
    76             for(int i=1;i<3;i++)  res=res*f[A[i][i]-1]%mod;
    77             res=res*f[A[0][0]]%mod;
    78             ans=(ans+res)%mod;
    79         }
    80         printf("%lld
    ",ans);
    81     }
    82     return 0;
    83 }
  • 相关阅读:
    [LeetCode] 44. Wildcard Matching
    [LeetCode] 1431. Kids With the Greatest Number of Candies
    [LeetCode] 47. Permutations II
    [LeetCode] 77. Combinations
    [LeetCode] 40. Combination Sum II
    [LeetCode] 39. Combination Sum
    [LeetCode] 213. House Robber II
    [LeetCode] 198. House Robber
    [LeetCode] 338. Counting Bits
    [LeetCode] 259. 3Sum Smaller
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/7363891.html
Copyright © 2020-2023  润新知