BZOJ#4894. 天赋


4894: 天赋

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 153  Solved: 121

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

Problem:
求有向图的生成树个数
 
Solution:
还是采用Matrix-tree定理来解决
我们的D为入度或者出度(随便用一个)
再去掉某行某列时,必须去掉根所在的行和列
 

附上代码:
#include<bits/stdc++.h>
using namespace std;
const int N=310,mod=1e9+7;
int D[N][N],A[N][N];
long long C[N][N];
int n;
char str[N];
long long Guass()
{
    long long ans=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++) 
        {
            long long a=C[i][i],b=C[j][i];
            while(b)
            {
                long long t=a/b;a%=b;swap(a,b);
                for(int k=i;k<=n;k++) C[i][k]=((C[i][k]-t*C[j][k])%mod+mod)%mod,swap(C[i][k],C[j][k]);
                ans=-ans;
            }
        }
        if(!C[i][i]) return 0;
        ans=ans*C[i][i]%mod;
    }
    ans=(ans%mod+mod)%mod;
    return ans;
}

int main()
{
    freopen("a.in","r",stdin);
    scanf("%d",&n);
    for(int i=0;i<n;i++) 
    {
        scanf("%s",str);
        for(int j=0;j<n;j++) 
        {
            A[i][j]=str[j]-'0';
            if(A[i][j]) D[j][j]++;
        }
    }
    for(int i=1;i<n;i++) 
        for(int j=1;j<n;j++) 
        C[i][j]=((D[i][j]-A[i][j])%mod+mod)%mod;
    n--;
    printf("%lld
",Guass());

    return 0;
}
 
 
 
 
 
 
 
 
 
 
原文地址:https://www.cnblogs.com/Heey/p/9131608.html