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_{v\in V,\ v\ne 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\n",ans);
81     }
82     return 0;
83 }

 

posted @ 2017-08-15 10:51  Kayden_Cheung  阅读(780)  评论(0编辑  收藏  举报
//目录