Solution -「JSOI2008」「洛谷 P4208」最小生成树计数
\(\mathcal{Description}\)
link.
给定带权简单无向图,求其最小生成树个数。
顶点数 \(n\le10^2\),边数 \(m\le10^3\),相同边权的边数不超过 \(10\)。
\(\mathcal{Solution}\)
先说一个引理:对于一个图的任意两棵最小生成树,其边权集合相等。
简单证明一下,设有两个最小生成树的边权集合 \(\{\dots,a,b,\dots\},\{\dots,c,d,\cdots\}\)(省略号处相等,不降排列)。相当于第一棵最小棵树的 \(a,b\) 边替换为了 \(c,d\) 边形成第二棵。不妨设 \(c<a\le b<d\)。那么在第一棵树里先删去 \(a,b\) 边,此时图由三个联通块。加入 \(c\),显然 \(a,b\) 中的一条是能够再加入的。所以加入 \(d\) 不优,第二棵不是最小生成树,矛盾。
借此,先跑出一棵最小生成树,记为 \(T\),并得到每种边权的出现次数。枚举每种边权 \(w\),把在 \(T\) 中且边权不为 \(w\) 的边加入图,并加入边权为 \(w\) 的所有边。注意加入边权为 \(w\) 的边前需要缩点以保证不会漏选其余边。矩阵树求出此时生成树个数,最后乘法原理乘起来就得到答案了。复杂度 \(\mathcal O(n^3)\)。
\(\mathcal{Code}\)
#include <cstdio>
#include <algorithm>
#define fr first
#define sc second
const int MOD = 31011, MAXN = 100, MAXM = 1000;
int n, m, fa[MAXN + 5], col[MAXN + 5], K[MAXN + 5][MAXN + 5];
bool used[MAXM + 5];
std::pair<int, std::pair<int, int> > eset[MAXM + 5];
inline void init ( const int n ) { for ( int i = 1; i <= n; ++ i ) fa[i] = i; }
inline int find ( const int x ) { return x ^ fa[x] ? fa[x] = find ( fa[x] ) : x; }
inline bool unite ( const int a, const int b ) {
int u = find ( a ), v = find ( b );
return u ^ v ? fa[u] = v, true : false;
}
inline void add ( const int u, const int v ) {
++ K[u][u], ++ K[v][v], -- K[u][v], -- K[v][u];
if ( K[u][v] < 0 ) K[u][v] += MOD;
if ( K[v][u] < 0 ) K[v][u] += MOD;
}
inline int det ( const int n ) {
int ret = 1, swp = 1;
for ( int i = 1; i < n; ++ i ) {
for ( int j = i + 1; j < n; ++ j ) {
for ( ; K[j][i]; std::swap ( K[i], K[j] ), swp *= -1 ) {
int d = K[i][i] / K[j][i];
for ( int k = i; k < n; ++ k ) K[i][k] = ( K[i][k] - d * K[j][k] + MOD ) % MOD;
}
}
if ( ! ( ret = ret * K[i][i] % MOD ) ) return 0;
}
return ( ret * swp + MOD ) % MOD;
}
int main () {
scanf ( "%d %d", &n, &m );
for ( int i = 1, u, v, w; i <= m; ++ i ) {
scanf ( "%d %d %d", &u, &v, &w );
eset[i] = { w, { u, v } };
}
sort ( eset + 1, eset + m + 1 ), init ( n );
int cnt = 0;
for ( int i = 1; i <= m && cnt < n - 1; ++ i ) {
if ( unite ( eset[i].sc.fr, eset[i].sc.sc ) ) {
++ cnt, used[i] = true;
}
}
if ( cnt < n - 1 ) return puts ( "0" ), 0;
int ans = 1;
for ( int i = 1, j; i <= m; i = j + 1 ) {
init ( n );
for ( j = 1; j <= m; ++ j ) {
if ( used[j] && eset[i].fr ^ eset[j].fr ) {
unite ( eset[j].sc.fr, eset[j].sc.sc );
}
}
int blk = 0;
for ( j = 1; j <= n; ++ j ) if ( j == fa[j] ) col[j] = ++ blk;
for ( j = 1; j <= n; ++ j ) col[j] = col[find ( j )];
for ( j = 1; j <= blk; ++ j ) for ( int k = 1; k <= blk; ++ k ) K[j][k] = 0;
for ( j = i; j <= m; ++ j ) {
add ( col[eset[j].sc.fr], col[eset[j].sc.sc] );
if ( j == m || eset[j].fr ^ eset[j + 1].fr ) break;
}
ans = ans * det ( blk ) % MOD;
}
printf ( "%d\n", ans );
return 0;
}
Solution -「JSOI2008」「洛谷 P4208」最小生成树计数的更多相关文章
- 「区间DP」「洛谷P1043」数字游戏
「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...
- 洛谷 P1596 [USACO10OCT]湖计数Lake Counting
题目链接 https://www.luogu.org/problemnew/show/P1596 题目描述 Due to recent rains, water has pooled in vario ...
- 洛谷P1144 最短路计数(SPFA)
To 洛谷.1144 最短路计数 题目描述 给出一个N个顶点M条边的无向无权图,顶点编号为1-N.问从顶点1开始,到其他每个点的最短路有几条. 输入输出格式 输入格式: 输入第一行包含2个正整数N,M ...
- 洛谷 1144 最短路计数 bfs
洛谷1144 最短路计数 传送门 其实这道题目的正解应该是spfa里面加一些处理,,然而,,然而,,既然它是无权图,,那么就直接bfs了,用一个cnt记录一下每一个点的方案数,分几种情况讨论一下转移, ...
- 洛谷 P4017 最大食物链计数
洛谷 P4017 最大食物链计数 洛谷传送门 题目背景 你知道食物链吗?Delia生物考试的时候,数食物链条数的题目全都错了,因为她总是重复数了几条或漏掉了几条.于是她来就来求助你,然而你也不会啊!写 ...
- 动态规划 洛谷P4017 最大食物链计数——图上动态规划 拓扑排序
洛谷P4017 最大食物链计数 这是洛谷一题普及/提高-的题目,也是我第一次做的一题 图上动态规划/拓扑排序 ,我认为这题是很好的学习拓扑排序的题目. 在这题中,我学到了几个名词,入度,出度,及没有环 ...
- Solution -「CTS 2019」「洛谷 P5404」氪金手游
\(\mathcal{Description}\) Link. 有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ...
- Solution -「JSOI 2019」「洛谷 P5334」节日庆典
\(\mathscr{Description}\) Link. 给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的). \(|S|\le3\time ...
- Solution -「洛谷 P4372」Out of Sorts P
\(\mathcal{Description}\) OurOJ & 洛谷 P4372(几乎一致) 设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...
随机推荐
- 随机数Random 和枚举enum
(一):生成随机数 要指定的话 需要在方法中指定最大的值 nextint(10)意思是 下一个的数是10需要导包:import java.util.Random; (二)枚举 enum 的语法和 ...
- “老”的Flexbox和“新”的Flexbox
本文由大漠根据Chris Coyier的<"Old" Flexbox and "New" Flexbox>所译,整个译文带有我们自己的理解与思想,如 ...
- [爱偷懒的程序员系列]-Section 1. “懒”是一切需求的根源
一直认为"懒"推进了科技的发展,因为"懒"而促生了各种各样的需求.科技的进步加速了各种信息的交互频率,站在台面上说是因为业务需要提高效率,成本需要降低,服务需要 ...
- NPOI Excel导入Invalid header signature
excel是从网页下载或者其他第三方软件导出的解决方法:使用excel打开,另存为2003版的excel,再导入就好了或者保存为 xlsx
- C# 类的继承问题 正方形周长面积计算问题
1. 设计编写一个控制台应用程序,练习类的继承. (1) 编写一个抽象类 People,具有"姓名","年龄"字段,"姓名"属性,Work ...
- MyCms 开源自媒体系统后台 角色管理&管理员管理操作说明
角色管理 功能说明 一.添加角色基本信息 填写角色名称.简要描述(一般以角色功能.职位等信息来命名) 二.角色授权 点击右侧的"授权"按钮,进行对角色授权,选择需要授权的功能模块后 ...
- openssl基本原理 + 生成证书(转)
https://blog.csdn.net/cpcpcp123/article/details/108885922 https://liruzhen.blog.csdn.net/article/det ...
- gin框架中的中间件
全局中间件 所有请求都经过此中间件 中间件中设置值 func MiddleWare() gin.HandlerFunc { return func(context *gin.Context) { t ...
- golang中数组指针和指针数组当做函数参数如何修改数组中的值
先理解:数组指针它的类型时指针,指针数组它的类型时数组 1. 数组指针当做函数的参数 package main import "fmt" func changeData(dataA ...
- UncLutter
在 Mac 上「速记」的正确姿势:Unclutter 现代人的大脑,每天都会被大量有用,或无用的东西充斥着,过多「思想垃圾」的沉重负担就容易导致失忆.也就是说,你很可能会记得一个无关紧要,但给你留下深 ...