生成树计数(草稿)

来源:互联网 发布:轩辕剑崆峒印进阶数据 编辑:程序博客网 时间:2024/06/03 17:35

生成树计数

这两天阴差阳错的研究了邹等周冬前辈的两篇论文~~

理论

图的关联矩阵

对于无向图 G ,我们定义它的关联矩阵 B 是一个 n×m 的矩阵,并且满足:如果 ek=(vi,vj) ,那么 BikBjk 一个为 1 ,另一个为1 ,而第 k 列其它元素均为 0

举例说明:
1

对于此图 G ,其矩阵如下:

110101011

Kirchhoff 矩阵

为研究 B 的性质,我们需要考察一下 BB转置矩阵(把矩阵 A 的行换成相应的列,得到的新矩阵称为 A 的转置矩阵,记作 ATBT 的乘积,根据矩阵乘法法则,我们可以得到:

BBTij=k=1mBikBTkj=k=1mBikBjk

可以发现:

  • i=j 时, BBTij=vi
  • ij
    • 如果存在 e(vi,vj) ,那么 BBTij=1
    • 否则 BBTij=0

BBTij 即为图的 Kirchhoff 矩阵

对于无向图 G ,它的 Kirchhoff 矩阵 C 定义为它的度数矩阵 D 减去他的邻接矩阵 A

Matrix-Tree 定理

本体

对于一个无向图 G ,他的生成树个数等于其 Kirchhoff 矩阵任何一个 n1 阶主子式的行列式的绝对值。

n1 阶主子式:任取一个 r ,将 C 的第 r 行和第 r 列同时删去后的新矩阵,用 Cr 表示。

证明

以后再说……

应用

[bzoj1002]轮状病毒[FJOI2007]

Time Limit: 1 Sec Memory Limit: 162 MB

题目描述

轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的。一个 N 轮状基由圆环上 N 个不同的基原子和圆心处一个核原子构成的, 2 个原子之间的边表示这 2 个原子之间的信息通道。如下图所示:
1

N 轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有 16 个不同的 3 轮状病毒,如下图所示
2

现给定 N( N100 ),编程计算有多少个不同的 N 轮状病毒

输入格式

第一行有 1 个正整数 N

输出格式

计算出的不同的 N 轮状病毒数输出

样例输入

3

样例输出

16


这道题是一道很明显地在考察 Matrix-Tree 定理,但是我们不能直接用程序计算,这样会超时,我们可以应用此定理推出一个递推式:

f[i]=3×f[i1]f[i2]+2

然后本题并没有让我们取模输出,故要用到高精度。

其实还可以用矩阵快速幂再优化一下递推,不过没加就 AC 了十年前的省选还是简单啊

#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int MAXN=105;int n;struct BN{    int num[105],len;    BN(){memset(num,0,sizeof(num));len=-1;}    void adjust()    {        for(int i=0;i<=len;i++)        if(num[i]>9)        {            num[i+1]+=num[i]/10;num[i]%=10;            len=max(len,i+1);        }        for(int i=0;i<=len;i++)        if(num[i]<0)        {            num[i-1]-=(-num[i])/10;num[i]=10-((-num[i])%10);        }        while(!num[len]) len--;    }    BN operator * (int x)const    {        BN res=*this;        for(int i=0;i<=len;i++) res.num[i]*=x;        res.adjust();        return res;    }    BN operator + (int x)const    {        BN res=*this;        for(int i=0;i<=len||x;i++) res.num[i]+=x%10,x/=10;        res.adjust();        return res;    }    BN operator - (BN x)const    {        BN res;        for(int i=0;i<=max(len,x.len);i++) res.num[i]-=x.num[i];        res.adjust();        return res;    }} f[MAXN];int main(){    int i;    scanf("%d",&n);    f[1]=BN()+1;f[2]=BN()+5;    for(i=3;i<=n;i++)        f[i]=f[i-1]*3-f[i-2]+2;    for(i=f[n].len;i>=0;i--) putchar(f[n].num[i]+'0');    printf("\n");    return 0;}
0 0
原创粉丝点击