当前位置: 首页 > news >正文

2024.8.24


130124202408241009


DATE #:20240824

ITEM #:DOC

WEEK #:SATURDAY

DAIL #:捌月廿壹

TAGS
< BGM = "风屿--闫东炜" >
< theme = oi-graph theory  >
< [NULL] >
< [空] > 
< [空] >
``` 与风为名,屿之齐鸣。——风屿 ```

## LGV引理

LGV 引理,全称 Lindstrom-Gessel-Viennot lemma

用于求解DAG上的不相交路径数,也就是生成树数量

内容:

  • 经典

给出一个无向无权图,设 A 为邻接矩阵, D 为度数矩阵(D[i][i]=节点 i 的度数,其他的无值)。

则基尔霍夫(Kirchhoff)矩阵即为 : K=D−A

然后令 K′ 为 K 去掉第k行与第k列(k任意)的结果(n−1阶主子式),

det⁡(K′) 即为该图的生成树个数。

  • 加权扩展

容易理解 : 带重边的情况,上面的经典矩阵树定理也是能够处理的。

根据乘法原理,对于某种生成树的形态,其贡献为每条边重的次数的乘积

如果把重边次数理解成权值的话,那么矩阵树定理求的就是 : 所有生成树边权乘积的总和。

(这里注意度数矩阵变成了相邻边的权值和)

  • 有向扩展

前面都是无向图,神奇的是有向图的情况也是可以做的。

(邻接矩阵 A 的意义同有向图邻接矩阵)

那么现在的矩阵 D 就要变一下了。

D [ i ] [ i ] = ∑ j = 1 n A [ j ] [ i ] D[i][i]=\sum_{j=1}^nA[j][i] D[i][i]=j=1nA[j][i] ,即到该点的边权总和(入)

此时求的就是外向树 (从根向外)

D [ i ] [ i ] = ∑ j = 1 n A [ j ] [ i ] D[i][i]=\sum_{j=1}^nA[j][i] D[i][i]=j=1nA[j][i] ,即从从该点出发的边权总和(出)

此时求的就是内向树 (从外向根)

(如果考场上不小心忘掉了,可以手玩小样例)

(同样可以加权!)

此外,既然是有向的,那么就需要指定根

前面提过要任意去掉第 k 行与第 k 列,是因为无向图所以不用在意谁为根。

在有向树的时候需要理解为指定根,结论是 : 去掉哪一行就是那一个元素为根。

(来自command_block)矩阵树定理(+行列式) - 洛谷专栏 (luogu.com.cn)

证明


P6178 [模板]Matrix-Tree 定理

【模板】Matrix-Tree 定理

题目描述

给定一张 n n n 个结点 m m m 条边的带权图(可能为无向图,可能为有向图)。

定义其一个生成树 T T T 的权值为 T T T 中所有边权的乘积。

求其所有不同生成树的权值之和,对 1 0 9 + 7 10^9+7 109+7 取模。


注意:

  1. 本题中,有向图的生成树指的是 1 1 1 为根的外向树

  2. 两棵生成树 T 1 , T 2 T_1,T_2 T1,T2 不同,当且仅当存在存在一条边 e e e,满足 e ∈ T 1 , e ∉ T 2 e\in T_1,\ \ e\notin T_2 eT1,  e/T2

输入格式

第一行:三个整数 n , m , t n,m,t n,m,t,分别表示图的结点数量,边的数量和图的类型( t = 0 t=0 t=0 时为无向图, t = 1 t=1 t=1 时为有向图)。

接下来 m m m 行:每行三个整数 u , v , w u,v,w u,v,w

如果 t = 0 t=0 t=0,表示 u , v u,v u,v 之间有一条权值为 w w w 的无向边;

如果 t = 1 t=1 t=1,表示从 u u u v v v 有一条权值为 w w w 的有向边。

输出格式

第一行:一个整数 a n s ans ans,表示给定的图的生成树权值和对 1 0 9 + 7 10^9+7 109+7 取模的结果。

样例 #1

样例输入 #1

5 8 0
2 3 1
1 2 3
4 5 1
4 2 2
3 5 2
3 4 3
3 4 1
3 3 5

样例输出 #1

144

样例 #2

样例输入 #2

5 9 1
1 2 3
3 2 1
1 3 1
2 4 2
3 5 1
4 3 4
3 5 1
5 4 1
4 4 6

样例输出 #2

72

提示

【样例 1 1 1 解释】

样例 1 1 1 中的无向图如左图所示:

右图为其一个权值为 3 × 1 × 2 × 3 = 18 3\times 1\times 2\times 3=18 3×1×2×3=18 的生成树的例子。


【样例 2 2 2 解释】

样例 2 2 2 中的有向图如左图所示:

右图为其一个权值为 1 × 1 × 1 × 2 = 2 1\times 1\times 1\times 2=2 1×1×1×2=2 的生成树(以 1 1 1 为根的外向树)的例子。


【数据范围】

对于 100 % 100\% 100% 的数据: 1 ≤ n ≤ 300 , 1 ≤ m ≤ 1 0 5 , t ∈ { 0 , 1 } , 1 ≤ u , v ≤ n , 1 ≤ w ≤ 1 0 9 1\leq n\leq 300,\ \ 1\leq m\leq 10^5,\ \ t\in \{0,1\},\ \ 1\leq u,v\leq n,\ \ 1\leq w\leq 10^9 1n300,  1m105,  t{0,1},  1u,vn,  1w109

对于测试点 1 , 2 , 3 , 4 , 5 , 6 1,2,3,4,5,6 1,2,3,4,5,6 t = 0 t=0 t=0;对于测试点 7 , 8 , 9 , 10 , 11 7,8,9,10,11 7,8,9,10,11 t = 1 t=1 t=1

图中 可能 存在重边和自环,重边算作多条边。

//2024.8.24
//by white_ice
//【模板】Matrix-Tree 定理 | P6178
//model
#include<bits/stdc++.h>
//ss#include"need.cpp"
using namespace std;
#define itn long long 
#define int long long 
constexpr int oo = 302;
constexpr itn mod = 1000000007;
itn n,m,t;
itn mp[oo][oo],out = 1;
__inline void lgv(){itn flag = 1;for (itn i=1;i<=n;i++){for (itn j=i+1;j<=n;j++){while (mp[j][i]){itn p = mp[i][i]/mp[j][i];for (itn k=i;k<=n;k++){mp[i][k] = (mp[i][k]-p*mp[j][k]+mod)%mod;swap(mp[i][k],mp[j][k]);}flag *= -1;}}(out *= mp[i][i])%=mod;}out = (out*flag+mod)%mod;
}
main(void){//fre();cin.tie(0)->sync_with_stdio(0);cin >> n >> m >> t;for (itn a,b,c,i=1;i<=m;i++){cin >> a >> b >> c;  a--,b--;if(!t){mp[a][a] = (mp[a][a]+c)%mod;mp[b][b] = (mp[b][b]+c)%mod;mp[a][b] = (mp[a][b]-c+mod)%mod;mp[b][a] = (mp[b][a]-c+mod)%mod;}else {mp[b][b] = (mp[b][b]+c)%mod;mp[b][a] = (mp[b][a]-c+mod)%mod;}}n--;lgv();cout << out << '\n';exit(0);
}

P4336 [SHOI2016] 黑暗前的幻想乡

[SHOI2016] 黑暗前的幻想乡

题目背景

四年一度的幻想乡大选开始了,最近幻想乡最大的问题是很多来历不明的妖怪涌入了幻想乡,扰乱了幻想乡昔日的秩序。但是幻想乡的建制派妖怪(人类)博丽灵梦和八云紫等人整日高谈所有妖怪平等,幻想乡多元化等等,对于幻想乡目前面临的种种大问题却给不出合理的解决方案。

风见幽香是幻想乡里少有的意识到了问题严重性的大妖怪。她这次勇敢地站了出来参加幻想乡大选,提出包括在幻想乡边境建墙(并让人类出钱),大力开展基础设施建设挽回失业率等一系列方案,成为了大选年出人意料的黑马并顺利地当上了幻想乡的大统领。

题目描述

幽香上台以后,第一项措施就是要修建幻想乡的公路。幻想乡一共有 n n n 个城市,之前原来没有任何路。幽香向选民承诺要减税,所以她打算只修 n − 1 n-1 n1 条公路将这些城市连接起来。但是幻想乡有正好 n − 1 n-1 n1 个建筑公司,每个建筑公司都想在修路的过程中获得一些好处。虽然这些建筑公司在选举前没有给幽香钱,幽香还是打算和他们搞好关系,因为她还指望他们帮她建墙。所以她打算让每个建筑公司都负责一条路来修。

每个建筑公司都告诉了幽香自己有能力负责修建的路是哪些城市之间的。所以幽香打算 n − 1 n - 1 n1 条能够连接幻想乡所有城市的边,然后每条边都交给一个能够负责该边的建筑公司修建,并且每个建筑公司都恰好修建一条边。

幽香现在想要知道一共有多少种可能的方案呢?两个方案不同当且仅当它们要么修的边的集合不同,要么边的分配方式不同。

输入格式

第一行包含一个整数 n n n,表示城市个数。

2 2 2 到第 n n n 行,第 ( i + 1 ) (i + 1) (i+1) 行表示 第 i i i 个建筑公司可以修建的路的列表:以一个非负整数 m i m_i mi 开头,表示其可以修建条路的条数;接下来有 m i m_i mi 对整数 u , v u, v u,v,每对数表示一条边的两个端点。其中不会出现重复的边,也不会出现自环。

输出格式

输出一行一个整数,表示所有可能的方案数对 1 0 9 + 7 10^9+7 109+7 取模的结果。

样例 #1

样例输入 #1

4
2 3 2 4 2
5 2 1 3 1 3 2 4 1 4 3
4 2 1 3 2 4 1 4 2

样例输出 #1

17

提示

数据规模与约定
  • 对于 20 % 20\% 20% 的测试点, n ≤ 5 n \le 5 n5
  • 对于 50 % 50\% 50% 的测试点, n ≤ 8 n \le 8 n8
  • 对于 60 % 60\% 60% 的测试点, n ≤ 10 n \le 10 n10
  • 对于 100 % 100\% 100% 的测试点, 2 ≤ n ≤ 17 2 \leq n \le 17 2n17 0 ≤ m i ≤ n ( n − 1 ) 2 0 \leq m_i \leq \frac{n(n - 1)}{2} 0mi2n(n1) 1 ≤ u , v ≤ n 1 \leq u, v \leq n 1u,vn
//2024.8.24
//by white_ice
//[SHOI2016] 黑暗前的幻想乡 | P4336
//LGV,容斥
#include<bits/stdc++.h>
//#include"need.cpp"
using namespace std;
#define itn long long 
#define int long long 
constexpr int oo = 20;
constexpr int mod = 1e9+7;
itn n,m;
itn mp[oo][oo];
vector<pair<int,int>> q[oo];
__inline int det(){int out=1;for(int i=1;i<=n;++i){int p=-1;for(int j=i;j<=n;++j)if(mp[i][j]){p=j;break;}if(!~p) return 0;if(p!=i){swap(i,p);out*=-1;}for(int j=i+1;j<=n;++j){while(mp[j][i]){int tmp=mp[j][i]/mp[i][i];for(int k=i;k<=n;++k){mp[j][k]-=1ll*tmp*mp[i][k]%mod;mp[j][k]=(mp[j][k]%mod+mod)%mod;} if(!mp[j][i]){break;}swap(mp[i],mp[j]);out*=-1;}}out=out*mp[i][i]%mod;}return out;
}
main(void){//fre();cin.tie(0)->sync_with_stdio(0);cin >> n;n--;for (itn x,y,i=1;i<=n;i++){cin >> m;while (m--){cin >> x >> y;q[i].push_back(make_pair(x,y));}}itn out = 0;for(int i=1;i<(1<<n);++i){memset(mp,0,sizeof(mp));int cnt=0;for(int j=1;j<=n;++j){if(!(i&(1<<(j-1)))){continue;}++cnt;for(int k=0;k<q[j].size();++k){int x=q[j][k].first,y=q[j][k].second;++mp[x][y],++mp[y][x];--mp[x][x],--mp[y][y];}}out=(out+((cnt&1)?-1:1)*det())%mod;}out = (out+mod)%mod;cout << out << flush;exit(0); 
}

考虑当没有每个公司只能修一条路的限制,那么就直接计数,LGV求解生成树即可

观察数据范围,很难不发现,n很小,可以状压枚举每种选k个公司给方案

每次将枚举的公司所能修的路加入矩阵并求解生成树

之后考虑容斥解题,记 f i f_i fi k = i k=i k=i时可能的方案数

那么答案就是
∑ f 1 − ∑ f 2 + ∑ f 3 ⋯ ± ∑ f n \sum f_1-\sum f_2 +\sum f_3 \dots \pm \sum f_n f1f2+f3±fn
当然,符号正负取决于选数个数的奇偶性

如此枚举即可

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • iPhone抹掉数据后能恢复吗?详解数据恢复的可能性与方法
  • 面向对象02:构造器详解
  • VScode 连接远程服务器
  • CLIP-VIT-L + Qwen 多模态源码阅读 - 语言模型篇(3)
  • 在vs+QT中使用QT的库(multimedia.lib)
  • 以简单的例子从头开始建spring boot web多模块项目(一)
  • 面向对象08:什么是多态
  • gping
  • sqli-labsSQL手工注入第26-30关
  • Android PopupWindow弹窗动态显示在View的上下方,
  • Bigtop 从0开始(上)
  • 从匿名内部类到Lambda表达式:Java编程的优雅进化
  • Challenge——spfa
  • 文件IO和多路复用IO
  • Flink入门(五)--Flink算子
  • dva中组件的懒加载
  • exif信息对照
  • javascript 哈希表
  • LeetCode18.四数之和 JavaScript
  • leetcode98. Validate Binary Search Tree
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • PHP的Ev教程三(Periodic watcher)
  • React-Native - 收藏集 - 掘金
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • Vue全家桶实现一个Web App
  • 浮现式设计
  • 简单实现一个textarea自适应高度
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 因为阿里,他们成了“杭漂”
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • 7行Python代码的人脸识别
  • Nginx实现动静分离
  • 扩展资源服务器解决oauth2 性能瓶颈
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • # wps必须要登录激活才能使用吗?
  • # 数仓建模:如何构建主题宽表模型?
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #VERDI# 关于如何查看FSM状态机的方法
  • %3cli%3e连接html页面,html+canvas实现屏幕截取
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (12)目标检测_SSD基于pytorch搭建代码
  • (14)Hive调优——合并小文件
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (9)STL算法之逆转旋转
  • (安卓)跳转应用市场APP详情页的方式
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (每日一问)计算机网络:浏览器输入一个地址到跳出网页这个过程中发生了哪些事情?(废话少说版)
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (一)UDP基本编程步骤
  • .gitignore文件设置了忽略但不生效
  • .Net 4.0并行库实用性演练
  • .net framework profiles /.net framework 配置
  • .NET 解决重复提交问题
  • .NET 中让 Task 支持带超时的异步等待