• 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("
    ");
     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
    ",det(n));
    56 }
  • 相关阅读:
    预备作业02:体会做中学(Learning By Doing)
    寒假作业01
    20210418第 237 场周赛(一)
    机器学习第七堂课20210415
    云计算与信息安全第七节课20210413
    操作系统第七堂课2021年0412内存管理基础
    机器学习第六堂课20210408
    云计算与信息安全第六节课20210406
    机器学习第五节课20210401
    云计算与信息安全第五堂课20210330
  • 原文地址:https://www.cnblogs.com/stranger-/p/9542920.html
Copyright © 2020-2023  润新知