BZOJ 4894 有向图 外向生成树个数

4894: 天赋

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 191  Solved: 150
[Submit][Status][Discuss]

Description

小明有许多潜在的天赋,他希望学习这些天赋来变得更强。正如许多游戏中一样,小明也有n种潜在的天赋,但有
一些天赋必须是要有前置天赋才能够学习得到的。也就是说,有一些天赋必须是要在学习了另一个天赋的条件下才
能学习的。比如,要想学会"开炮",必须先学会"开枪"。一项天赋可能有多个前置天赋,但只需习得其中一个就可
以学习这一项天赋。上帝不想为难小明,于是小明天生就已经习得了1号天赋-----"打架"。于是小明想知道学习完
这n种天赋的方案数,答案对1,000,000,007取模。

 

Input

第一行一个整数n。
接下来是一个n*n的01矩阵,第i行第j列为1表示习得天赋j的一个前置天赋为i。
数据保证第一列和主对角线全为0。
n<=300

 

Output

第一行一个整数,问题所求的方案数。

 

Sample Input

8
01111111
00101001
01010111
01001111
01110101
01110011
01111100
01110110

Sample Output

72373

解析    本题其实就是求以1为起点  外向生成树的个数   还是用基尔霍夫满矩阵来写

定理题,证明过程比较难,记下结论吧

有向树:对于一个有向图,如果无视边的方向是一棵树,那么此有向图就称为有向树

外向树:有向树的特殊情况,下同,所有边的方向都是从根指向叶子

内向树:所有边的方向都是从叶子指向根

 

对于n个点的有向图,求出外向生成树个数:(其实就是这道题)

①先定义一个n*n的矩阵,a[i][i]初始化为i点的入度其它为0

②如果存在一条i到j的边,那么a[i][j]-1,最后删掉根的那一行和那一列

③求出对应(n-1)*(n-1)的行列式的值就是答案

 

对于有向图求内向生成树的个数只要将入度换成出度计算方式一样

 1 #include <bits/stdc++.h>
 2 #define pb push_back
 3 #define mp make_pair
 4 #define fi first
 5 #define se second
 6 #define all(a) (a).begin(), (a).end()
 7 #define fillchar(a, x) memset(a, x, sizeof(a))
 8 #define huan printf("\n");
 9 #define debug(a,b) cout<<a<<" "<<b<<" ";
10 using namespace std;
11 typedef long long ll;
12 const int maxn=310,maxm=100,inf=0x3f3f3f3f;
13 const ll mod=1000000007;
14 ll a[maxn][maxn];
15 ll det(int n)
16 {
17     ll ans = 1;
18     for (int i = 2; i <= n; i++)
19     {
20         for (int j = i + 1; j <= n; j++)
21         {
22             while (a[j][i] != 0)
23             {
24                 ll u = a[i][i] / a[j][i];
25                 for (int k = i; k <= n; k++)
26                 {
27                     ll t = (a[i][k] - (ll)a[j][k] * u % mod + mod)% mod;
28                     a[i][k] = a[j][k];
29                     a[j][k] = t;
30                 }
31                 ans = -ans;
32             }
33         }
34         ans = ans * a[i][i]% mod;
35     }
36     if (ans < 0)
37     {
38         //ans=-ans;
39         ans += mod;
40     }
41     return ans;
42 }
43 char s[500];
44 int main()
45 {
46     int n;
47     scanf("%d",&n);
48     for(int i=1;i<=n;i++)
49     {
50         scanf("%s",s+1);
51         for(int j=1;j<=n;j++)
52             if(s[j]=='1')
53                 a[j][i]--,a[j][j]++;
54     }
55     printf("%lld\n",det(n));
56 }

 

posted @ 2018-08-27 16:24  灬从此以后灬  阅读(532)  评论(0编辑  收藏  举报