【BZOJ 1016】 [JSOI2008]最小生成树计数(matrix-tree定理做法)
【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1016
【题意】
【题解】
/*
接上一篇文章;
这里用matrix-tree定理搞最小生成树个数;
对于每一种相同边权的边;
当做一个阶段;
这个阶段,我们需要看看这个边权的边能连接哪些联通块;
这里的联通块可以缩为一个点;
这样就相当于在一些点中间插入边;
然后问你这些边能够生成的生成树的个数;
即每个阶段都做一遍matrix-tree定理;
martrix-treee定理想要做的话;
你得先得出一张图,最好弄出它的邻接矩阵;
然后可以这样吧。
把这张图缩点之后的节点都标成新的节点;
然后根据新添加进来的边;
建立一张新的图,
然后在这张新图上求生成树;
根据前一篇的分析可知这样的生成树一定是最小生成树的一部分;
建立新图的话也不会难吧;
如果节点之前没出现过就递增节点就好;
然后统计这张新图里面节点的个数;
然后处理出邻接矩阵和度数就能搞了;
不过这样处理会有重边的哦;
当然这个定理也能处理有重边的情况,所以不慌.
每次把生成树的个数根据乘法原则乘到答案上就好
(新的图上可能会有多个连通块,要每个连通块分别算,不然整张图都不是联通的,你再用
整张图去求的话会出错)
(初始化什么的一定要认真检查啊);
(这个行列式的求法不要用double类,不然精度不够,用int。。不知道为什么可以用int..)
*/
推荐一个题解吧
http://www.cnblogs.com/flipped/p/5769228.html
要记住是度数矩阵减去邻接矩阵啊.
【完整代码】
#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%lld",&x)
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 };
const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 };
const double pi = acos(-1.0);
const int N = 110;
const int M = 1e3 + 100;
const int MOD = 31011;
struct abc
{
int x, y, z;
};
int n, m,tot,cnt = 0;
int f[N],D[N][N],A[N][N],C[N][N],ka[N],g[N][N];
int bo[N];
abc bian[M];
double a[N][N];
vector <int> v[N];
long long ans = 1;
bool cmp1(abc a, abc b)
{
return a.z < b.z;
}
int ff(int x)
{
if (f[x] == x) return x;
else
return f[x] = ff(f[x]);
}
int fk(int x)
{
if (ka[x] == x) return x;
else
return ka[x] = fk(ka[x]);
}
int cl(int c[N][N], int n) {
int i, j, k, t, ret = 1;
for (i = 1; i<=n-1; i++) {
for (j = i + 1; j<=n-1; j++)
while (c[j][i]) {
t = c[i][i] / c[j][i];
for (k = i; k<n; k++)
c[i][k] = (c[i][k] - c[j][k] * t) % MOD;
swap(c[i], c[j]);
ret = -ret;
}
if (c[i][i] == 0)
return 0;
ret = ret*c[i][i] % MOD;
}
return (ret + MOD) % MOD;
}
int main()
{
//freopen("F:\\rush.txt", "r", stdin);
rei(n), rei(m);
rep1(i, 1, m)
rei(bian[i].x), rei(bian[i].y), rei(bian[i].z);
sort(bian + 1, bian + 1 + m,cmp1);
ans = 1;
rep1(i, 1, n)
f[i] = i,ka[i] = i;
rep1(i, 1, m)
{
int l = i, r = i;
while (r + 1 <= m && bian[r + 1].z == bian[l].z) r++;
rep1(j, 1, n)
rep1(jj, 1, n)
g[j][jj] = 0;
rep1(j, 1, n)
bo[j] = 0;
rep1(j, l, r)
{
int x = bian[j].x, y = bian[j].y;
int r1 = ff(x), r2 = ff(y);
if (r1 != r2)
{
int rr1 = fk(r1), rr2 = fk(r2);
if (rr1 != rr2)
ka[rr1] = rr2;
bo[r1] = true, bo[r2] = true;
g[r1][r2]++, g[r2][r1]++;
}
}
rep1(j, 1, n)
v[j].clear();
rep1(j, 1, n)
if (bo[j])
v[fk(j)].push_back(j);
rep1(j,1,n)
if (int(v[j].size()) > 1)
{
rep1(k, 1, n)
rep1(kk, 1, n)
D[k][kk] = A[k][kk] = 0;
int len = v[j].size();
rep1(k,0,len-2)
rep1(l, k + 1, len - 1)
{
int x = v[j][k], y = v[j][l];
if (g[x][y])
{
D[k+1][k+1] += g[x][y], D[l+1][l+1] += g[x][y];
A[l+1][k+1] = A[k+1][l+1] = g[x][y];
}
}
rep1(k, 1,len )
rep1(kk, 1, len)
C[k][kk] = D[k][kk] - A[k][kk];
tot = len;
ans = (ans*cl(C,len)) % MOD;
}
rep1(j, l, r)
{
int x = bian[j].x, y = bian[j].y;
int r1 = ff(x), r2 = ff(y);
if (r1 != r2)
{
f[r1] = r2;
cnt++;
}
}
rep1(j, 1, n)
ka[j] = f[j];
i = r;
}
if (cnt != n - 1)
return puts("0"),0;
printf("%lld\n", ans);
return 0;
}
【BZOJ 1016】 [JSOI2008]最小生成树计数(matrix-tree定理做法)的更多相关文章
- 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]最小生成树计数( kruskal + dfs )
不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...
- [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】
题目链接:BZOJ - 1016 题目分析 最小生成树的两个性质: 同一个图的最小生成树,满足: 1)同一种权值的边的个数相等 2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性 ...
- [BZOJ]1016 JSOI2008 最小生成树计数
最小生成树计数 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同 ...
- BZOJ 1016 [JSOI2008]最小生成树计数 ——Matrix-Tree定理
考虑从小往大加边,然后把所有联通块的生成树个数计算出来. 然后把他们缩成一个点,继续添加下一组. 最后乘法原理即可. 写起来很恶心 #include <queue> #include &l ...
- bzoj 1016: [JSOI2008]最小生成树计数【dfs+克鲁斯卡尔】
有一个性质就是组成最小生成树总边权值的若干边权总是相等的 这意味着按边权排序后在权值相同的一段区间内的边能被选入最小生成树的条数是固定的 所以先随便求一个最小生成树,把每段的入选边数记录下来 然后对于 ...
- 【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 ...
- @总结 - 7@ 生成树计数 —— matrix - tree 定理(矩阵树定理)与 prüfer 序列
目录 @0 - 参考资料@ @0.5 - 你所需要了解的线性代数知识@ @1 - 矩阵树定理主体@ @证明 part - 1@ @证明 part - 2@ @证明 part - 3@ @证明 part ...
随机推荐
- [Angular] Style HTML elements in Angular using ngStyle
We will learn how to make use of the ngStyle directive to directly add multiple style attributes to ...
- 使用ajax发送图片等文件
1.使用H5的FormData()对象,append()添加文件 2.processData: false, // 告诉jQuery不要去处理发送的数据 contentType: false, ...
- Php无限层级并显示层级数
今天在处理递归无限层级菜单时,遇到一个稍微烧脑的问题,如何显示当前节点所在的层级数.废话不多说,我们先看个直观的无限层级: <?php // 这里的arr是直接从数据库取出的,仅作为测试数据 $ ...
- Java基础学习总结(49)——Excel导入导出工具类
在项目的pom文件中引入 <dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifac ...
- [D3] Margin Convention with D3 v4
You can’t add axes to a chart if you don’t make room for them. To that end, the D3 community has ado ...
- C语言深度剖析-----多维数组和多维指针
多维数组和多维指针 指向指针的指针 指针变量同样也有传址调用和传值调用 case1:估算要5个字节的空间,实际只用前面3个字节,设计释放空的2字节 case2:扩充到10字节 二维数组与二维指针 二维 ...
- POJ 1364 King (UVA 515) 差分约束
http://poj.org/problem?id=1364 http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemi ...
- AE中Shapefile文件添加到SDE数据集
linder_lee 原文 AE中Shapefile文件添加到SDE数据集(c#) 主要完成用C#,通过AE将本地Shapefile文件导入到SDE的指定数据集下面. 首先说下思路: (1) 通过Op ...
- Android5.0(Lollipop) BLE蓝牙4.0+浅析demo连接(三)
作者:Bgwan链接:https://zhuanlan.zhihu.com/p/23363591来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. Android5.0(L ...
- PHP解决约瑟夫环问题
PHP解决约瑟夫环问题 一.总结 二.PHP解决约瑟夫环问题 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到 ...