【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 ...
随机推荐
- 让单选input框,不在被选中,添加disabled即可。输入框input的一些技巧
1.让单选input框,不在被选中,添加disabled即可 2.input的file文件对象的清空,只需要input.val("");就可以了.
- java hadoop file system API
org.apache.hadoop.fs Class FileSystem java.lang.Object org.apache.hadoop.fs.FileSystem All Implement ...
- BAT面试题 - 找一个无序实数数组中的最大差值
题目描写叙述: 一个无序的实数数组a[i].要求求里面大小相邻的实数的差的最大值.比方 double a[]={1,5,4,0.2,100} 这个无序的数组,相邻的数的最大差值为100-5=95. 题 ...
- 11.5 Android显示系统框架_Vsync机制_黄油计划_三个方法改进显示系统
5. Vsync机制5.1 黄油计划_三个方法改进显示系统vsync, triple buffering, vsync虚拟化 参考文档:林学森 <深入理解Android内核设计思想>第2版 ...
- HDU 5237 Base64
Base64 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Sub ...
- POJ 3134 - Power Calculus (IDDFS)
题意:求仅仅用乘法和除法最快多少步能够求到x^n 思路:迭代加深搜索 //Accepted 164K 1094MS C++ 840B include<cstdio> #include< ...
- PJSIP开源库详解
PJSIP是一个包含了SIP.SDP.RTP.RTCP.STUN.ICE等协议实现的开源库.它把基于信令协议SIP的多媒体框架和NAT穿透功能整合成高层次.抽象的多媒体通信API,这套API能够很容易 ...
- FeatureLayer,FeatureDataset,FeatureClass,Feature的区别与联系总结
duckweeds原文 FeatureLayer,FeatureDataset,FeatureClass,Feature几个概念一点点总结,欢迎指教 刚学AE,其中很多概念都模糊不清.经过一段时间的摸 ...
- swift学习第九天:可选类型以及应用场景
可选类型的介绍 注意: 可选类型时swift中较理解的一个知识点 暂时先了解,多利用Xcode的提示来使用 随着学习的深入,慢慢理解其中的原理和好处 概念: 在OC开发中,如果一个变量暂停不使用,可以 ...
- stm32的ADC规则组通道采样顺序设置
先看一下固件库手册 再看一下手册上的例子: 有两个通道,,并且顺序如下