生成树计数(草稿)

本文介绍了一种用于计算无向图生成树数量的方法——Matrix-Tree定理,并通过Kirchhoff矩阵来求解。同时,通过一道具体题目——bzoj1002轮状病毒,展示了如何利用该定理推导递推公式并实现高效算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

生成树计数

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

理论

图的关联矩阵

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

举例说明:
1

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

110101011

Kirchhoff 矩阵

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

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;
}
### 关于2024年蓝桥杯全国赛Java题目及解答 目前尚未有官方发布的具体关于2024年蓝桥杯全国赛Java组的正式试题和详细解答[^3]。然而,基于以往的比赛趋势以及参赛者的经验分享,可以推测出一些可能涉及的知识点和技术方向。 #### 可能考察的核心知识点 以下是根据历年真题总结出来的常见考点: 1. **基础算法** - 排序算法(快速排序、归并排序等) - 查找算法(二分查找、哈希表应用等) - 动态规划问题(背包问题变种、最长公共子序列等) 2. **数据结构** - 栈与队列的应用场景 - 图论基础知识(最短路径、最小生成树等) - 字符串处理技术(KMP匹配、Manacher算法等) 3. **数学逻辑** - 数论基本概念(最大公约数、欧拉函数计算等) - 组合计数方法及其优化技巧 - 概率统计初步理论 4. **编程能力测试** - 时间复杂度控制下的高效解决方案设计 - 边界条件考虑全面性的程序编写习惯养成 - 错误调试能力和异常捕获机制掌握程度评估 #### 解题策略建议 针对上述提到的各项技能领域,在实际竞赛过程中需要注意以下几点事项来提高得分概率: - 对于每一类问题都要熟悉至少一种标准解决办法,并能够灵活运用到不同情境下; - 学会合理分配时间给各个小问或者模块之间,优先完成自己更有把握的部分; - 编码之前先理清思路,草稿纸上画图辅助理解有助于减少返工次数; - 测试用例不仅要覆盖正常输入还要特别关注极端情况下的表现如何; ```java // 示例代码片段展示如何通过预定义数组模拟栈操作从而验证括号配对合法性 public class BracketValidator { public static boolean isValid(String s) { char[] stack = new char[s.length()]; int top = -1; for (char c : s.toCharArray()) { if (c == '(' || c == '{' || c == '['){ stack[++top] = c; // Push onto the stack }else{ if(top >= 0 && ((stack[top]=='('&&c==')') ||(stack[top]=='{'&&c=='}') ||(stack[top]=='['&&c==']')) ){ --top;// Pop from the stack when matching bracket found } else return false; } } return top == -1 ? true:false ; } } ``` 此段代码演示了一个简单的括号匹配器实现方式,适用于某些特定类型的字符串处理挑战题型之中[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值