【BZOJ】1016: [JSOI2008]最小生成树计数
题解
考虑kruskal
我们都是从边权最小的边开始取,然后连在一起
那我们选出边权最小的一堆边,然后这个图就分成了很多联通块,把每个联通块内部用矩阵树定理算一下生成树个数,再把联通块缩成一个大点,重复取下一个边权的边进行操作
好想然而不是很好写= =写起来感觉有点麻烦
模数非质数,用long double水一下过掉了
代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <bitset>
#include <queue>
#define enter putchar('\n')
#define space putchar(' ')
//#define ivorysi
#define pb push_back
#define mo 974711
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define MAXN 200005
#define eps 1e-12
using namespace std;
typedef long long int64;
typedef long double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 - '0' + c;
c = getchar();
}
res = res * f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
int N,M;
struct node {
int u,v,c;
friend bool operator < (const node &a,const node &b) {
return a.c < b.c;
}
}E[1005];
int fa[105],id[105],f[105][105],L[105],tot,D[105];
bool vis[105];
db g[105][105];
int64 ans = 1;
int getfa(int x) {
return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}
db Guass(int n) {
db res = 1;
for(int i = 2 ; i <= n ; ++i) {
int l = i;
for(int j = i + 1 ; j <= n ; ++j) {
if(fabs(g[j][i]) > fabs(g[l][i])) l = j;
}
if(i != l) {
res = -res;
for(int j = i ; j <= n ; ++j) {
swap(g[i][j],g[l][j]);
}
}
if(fabs(g[i][i]) == 0) return 0;
for(int j = i + 1 ; j <= n ; ++j) {
db t = g[j][i] / g[i][i];
for(int k = i ; k <= n ; ++k) {
g[j][k] -= g[i][k] * t;
}
}
}
for(int k = 2 ; k <= n ; ++k) {
res = res * g[k][k];
}
return res;
}
void dfs(int u,int n) {
vis[u] = 1;
L[++tot] = u;
D[u] = tot;
for(int i = 1 ; i <= n ; ++i) {
if(f[u][i]) {
if(!vis[i]) dfs(i,n);
}
}
}
void Process(int l,int r) {
memset(id,0,sizeof(id));
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
int cnt = 0;
for(int i = 1 ; i <= N ; ++i) {
if(!id[getfa(i)]) {
id[getfa(i)] = ++cnt;
}
}
for(int i = l ; i <= r ; ++i) {
int s = getfa(E[i].u),t = getfa(E[i].v);
if(s == t) continue;
f[id[s]][id[t]]++; f[id[t]][id[s]]++;
}
for(int i = 1 ; i <= cnt ; ++i) {
if(!vis[i]) {
tot = 0;
dfs(i,cnt);
if(tot == 1) continue;
memset(g,0,sizeof(g));
for(int j = 1 ; j <= tot ; ++j) {
int u = L[j];
for(int k = 1 ; k <= cnt ; ++k) {
if(f[u][k]) {
g[j][j] += f[u][k];
g[j][D[k]] -= f[u][k];
}
}
}
ans = ans * ((int64)(Guass(tot) + 0.5) % 31011) % 31011;
}
}
for(int i = l ; i <= r ; ++i) {
fa[getfa(E[i].v)] = getfa(E[i].u);
}
}
void Solve() {
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) fa[i] = i;
int u,v,c;
for(int i = 1 ; i <= M ; ++i) {
read(E[i].u);read(E[i].v);read(E[i].c);
fa[getfa(E[i].u)] = getfa(E[i].v);
}
for(int i = 2 ; i <= N ; ++i) {
if(getfa(i) != getfa(i - 1)) {
puts("0");
return;
}
}
for(int i = 1 ; i <= N ; ++i) fa[i] = i;
sort(E + 1,E + M + 1);
v = 0;int st = 0;
bool flag = 0;
for(int i = 1 ; i <= M ; ++i) {
if(E[i].c != v) {
if(st != 0) Process(st,i - 1);
st = i;
v = E[i].c;
flag = 1;
for(int j = 2 ; j <= N ; ++j) {
if(getfa(j) != getfa(j - 1)) {flag = 0;break;}
}
if(flag) break;
}
}
if(!flag) Process(st,M);
out(ans);enter;
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Solve();
}
【BZOJ】1016: [JSOI2008]最小生成树计数的更多相关文章
- BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )
不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...
- [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】
题目链接:BZOJ - 1016 题目分析 最小生成树的两个性质: 同一个图的最小生成树,满足: 1)同一种权值的边的个数相等 2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性 ...
- [BZOJ]1016 JSOI2008 最小生成树计数
最小生成树计数 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同 ...
- BZOJ.1016.[JSOI2008]最小生成树计数(Matrix Tree定理 Kruskal)
题目链接 最小生成树有两个性质: 1.在不同的MST中某种权值的边出现的次数是一定的. 2.在不同的MST中,连接完某种权值的边后,形成的连通块的状态是一样的. \(Solution1\) 由这两个性 ...
- bzoj 1016 [JSOI2008]最小生成树计数——matrix tree(相同权值的边为阶段缩点)(码力)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1016 就是缩点,每次相同权值的边构成的联通块求一下matrix tree.注意gauss里的 ...
- bzoj 1016: [JSOI2008]最小生成树计数【dfs+克鲁斯卡尔】
有一个性质就是组成最小生成树总边权值的若干边权总是相等的 这意味着按边权排序后在权值相同的一段区间内的边能被选入最小生成树的条数是固定的 所以先随便求一个最小生成树,把每段的入选边数记录下来 然后对于 ...
- BZOJ 1016 [JSOI2008]最小生成树计数 ——Matrix-Tree定理
考虑从小往大加边,然后把所有联通块的生成树个数计算出来. 然后把他们缩成一个点,继续添加下一组. 最后乘法原理即可. 写起来很恶心 #include <queue> #include &l ...
- 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)
1016: [JSOI2008]最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树 ...
- 1016: [JSOI2008]最小生成树计数
1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 6200 Solved: 2518[Submit][St ...
- 【BZOJ】1016: [JSOI2008]最小生成树计数 深搜+并查集
最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小 ...
随机推荐
- Spring MVC原理介绍
1.Spring Web MVC是什么 spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解 ...
- Elasticsearch技术解析与实战(四)shard&replica机制
序言 shard&replica机制 1.index包含多个shard 2.每个shard都是一个最小工作单元,承载部分数据,lucene实例,完整的建立索引和处理请求的能力 3.增减节点时, ...
- Xilinx Altera FPGA中的逻辑资源(Slices VS LE)比较
前言 经常有朋友会问我,“我这个方案是用A家的FPGA还是X家的FPGA呢?他们的容量够不够呢?他们的容量怎么比较呢?”当然,在大部分时候,我在给客户做设计的时候,直接会用到最高容量的产品,因为我们的 ...
- 微信小程序开发教程(六)配置——app.json、page.json详解
全局配置:app.json 微信小程序的全局配置保存在app.json文件中.开发者通过使用app.json来配置页面文件(pages)的路径.窗口(window)表现.设定网络超时时间值(netwo ...
- 博皮设计:HTML/CSS/Javascript 源码共享
首先感谢 sevennight 对我的大力帮助,由此他也成为了我的第一位园友:其次,由于本人并不了解 HTML/CSS,因此几乎都在 李宝亨 设计的 博皮源码 的基础上进行的修改:最后,为了获得 更加 ...
- 一个MMORPG的常规技能系统
广义的的说,和战斗结算相关的内容都算技能系统,包括技能信息管理.技能调用接口.技能目标查找.技能表现.技能结算.技能创生体(buff/法术场/弹道)管理,此外还涉及的模块包括:AI模块(技能调用者). ...
- zzd 的割草机(Lawnmower)
评测传送门 [题目描述] 已知花坛为一个 n * m 的矩形,草只会长在某些个格子上,zzd 有一个割草机,一开始,zzd 站在(1,1)处,面向(1,m)(面向右).每次 zzd 有两个选择(耗费一 ...
- C#中2个日期类型相减
DateTime startTime = Convert.ToDateTime("2017-1-9");DateTime endTime = Convert.ToDateTime( ...
- JS设计模式——10.门面模式
门面模式 这是一种组织性的模式,它可以用来修改类和对象的接口,使其更便于使用.它可以让程序员过得更轻松,使他们的代码变得更容易管理. 门面模式有两个作用: 简化类的接口 消除与使用她的客户代码之间的耦 ...
- css_清除浮动的4种方式
浮动布局和定位布局为css中布局的常用的两种布局方式,而且兼容性会比较好.随着flex的流行,以后会是主流,新的东西好用,兼容不太好.IE10以下不兼容flex布局. float布局会脱离文档流,对页 ...