考虑从小往大加边,然后把所有联通块的生成树个数计算出来。

然后把他们缩成一个点,继续添加下一组。

最后乘法原理即可。

写起来很恶心

#include <queue>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define maxn 1005
#define eps 1e-6
const int md=31011;
vector <int> v,to[maxn];
queue <int> q;
struct Edge{int u,v,w;}a[maxn];
int n,m,fa[maxn];
int b[maxn][maxn],inv[maxn];
int vcnt,du[maxn],list[maxn],vis[maxn];
bool cmp(Edge x,Edge y)
{return x.w<y.w;}
int gf(int k)
{if (fa[k]==k) return k; else return fa[k]=gf(fa[k]);}
int gauss(int n)
{
F(i,1,n) F(j,1,n) b[i][j]%=md;
int ret=1;
for (int i=1;i<n;++i)
{
for (int j=i+1;j<n;++j)
while (b[j][i])
{
int t=b[i][i]/b[j][i];
for (int k=i;k<n;++k)
b[i][k]=(b[i][k]-b[j][k]*t+md)%md;
for (int k=i;k<n;++k)
swap(b[i][k],b[j][k]);
ret=-ret;
}
if (b[i][i]==0) return 0;
ret=ret*b[i][i]%md;
}
return abs((ret+md)%md);
}
int main()
{
scanf("%d%d",&n,&m);
F(i,1,n) fa[i]=i;
F(i,1,m){scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);}
sort(a+1,a+m+1,cmp);
int now=1,ans=1;
while (now<=m)
{
int l=now,r=now;
vcnt=0;
memset(du,0,sizeof du);
F(i,1,n) to[i].clear();
while (a[r+1].w==a[r].w) r++;
now=r+1;
F(i,l,r)
{
int fl=gf(a[i].u),fr=gf(a[i].v);
to[fl].push_back(fr);
to[fr].push_back(fl);
if (fl!=fr) du[fl]++,du[fr]++;
}
memset(vis,0,sizeof vis);
F(i,1,n)
if (du[i]&&!vis[i])
{
v.clear();
memset(b,0,sizeof b);
memset(inv,0,sizeof inv);
q.push(i);inv[i]=1;vis[i]=1;
while (!q.empty())
{
int x=q.front();v.push_back(x);q.pop();
for (int j=0;j<to[x].size();++j)
if (!vis[to[x][j]])
q.push(to[x][j]),inv[to[x][j]]=1,vis[to[x][j]]=1;
}
for (int j=0;j<v.size();++j) list[v[j]]=j+1;
for (int j=0;j<v.size();++j)
for (int k=0;k<to[v[j]].size();++k)
if (inv[to[v[j]][k]])
{
b[list[v[j]]][list[v[j]]]++,b[list[v[j]]][list[to[v[j]][k]]]--;
}
ans*=gauss(v.size());
ans%=md;
}
F(i,l,r)
{
int fl=gf(a[i].u),fr=gf(a[i].v);
if (fl!=fr){fa[fl]=fr;}
}
}
int cnt=0;
F(i,1,n) if (fa[i]==i)
{
cnt++;
if (cnt==2) {printf("0\n"); return 0;}
}
printf("%d\n",ans);
}

  

BZOJ 1016 [JSOI2008]最小生成树计数 ——Matrix-Tree定理的更多相关文章

  1. BZOJ.1016.[JSOI2008]最小生成树计数(Matrix Tree定理 Kruskal)

    题目链接 最小生成树有两个性质: 1.在不同的MST中某种权值的边出现的次数是一定的. 2.在不同的MST中,连接完某种权值的边后,形成的连通块的状态是一样的. \(Solution1\) 由这两个性 ...

  2. bzoj 1016 [JSOI2008]最小生成树计数——matrix tree(相同权值的边为阶段缩点)(码力)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1016 就是缩点,每次相同权值的边构成的联通块求一下matrix tree.注意gauss里的 ...

  3. BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )

    不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理. ----------------------- ...

  4. [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】

    题目链接:BZOJ - 1016 题目分析 最小生成树的两个性质: 同一个图的最小生成树,满足: 1)同一种权值的边的个数相等 2)用Kruscal按照从小到大,处理完某一种权值的所有边后,图的连通性 ...

  5. [BZOJ]1016 JSOI2008 最小生成树计数

    最小生成树计数 题目描述 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同 ...

  6. bzoj 1016: [JSOI2008]最小生成树计数【dfs+克鲁斯卡尔】

    有一个性质就是组成最小生成树总边权值的若干边权总是相等的 这意味着按边权排序后在权值相同的一段区间内的边能被选入最小生成树的条数是固定的 所以先随便求一个最小生成树,把每段的入选边数记录下来 然后对于 ...

  7. 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)

    1016: [JSOI2008]最小生成树计数 Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树 ...

  8. 1016: [JSOI2008]最小生成树计数

    1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 6200  Solved: 2518[Submit][St ...

  9. @总结 - 7@ 生成树计数 —— matrix - tree 定理(矩阵树定理)与 prüfer 序列

    目录 @0 - 参考资料@ @0.5 - 你所需要了解的线性代数知识@ @1 - 矩阵树定理主体@ @证明 part - 1@ @证明 part - 2@ @证明 part - 3@ @证明 part ...

随机推荐

  1. Android 图片在SD卡及包下的存储

    public class FileBitmap { /** * 获取sd卡中的bitmap,bitmap可见 * * @param bitmap * 读取bitmap的路径 * @return bit ...

  2. run_test() 验证平台的入口

    Run,just run!    ——阿甘正传   一个简单的例子: module tb_top; dut u_dut (); initial begin run_test(); end config ...

  3. SPM-软件项目管理之感想

    这学期开始选择选修课的时候是需要把每节课都过一遍的.当我上完SPM那节课的时候,我就已经决定要选这门课了,尽管还有其他的课我都还没上过.由于这节课是双语教学-中文老师兼外籍老师,这样的方式感觉很新颖, ...

  4. [论文笔记] A Practical Architecture of Cloudification of Legacy Applications (2011, SERVICES)

    Dunhui Yu, Jian Wang, Bo Hu, Jianxiao Liu, Xiuwei Zhang, Keqing He, and Liang-Jie Zhang. 2011. A Pra ...

  5. vue+element ui项目总结点(四)零散细节概念巩固如vue父组件调用子组件的方法、拷贝数据、数组置空问题 等

    vue config下面的index.js配置host: '0.0.0.0',共享ip (假设你的电脑启动了这个服务我电脑一样可以启动)-------------------------------- ...

  6. POJ 1741 Tree (树的分治,树的重心)

    题意:给一棵树,n个节点,给定一个数k,求任意满足dist(a,b)<=k的点对的数量. 思路: 这道题的思路比较简单,但是细节很多. 此题可以用分治法,如何分治? (1)如果path(a,b) ...

  7. idea 发布和本地测试问题

    1.maven本地打包成jar 提示[错误: 找不到或无法加载主类]修改 配置maven ---->Runner---->VM Optins [-DarchetypeCatalog=loc ...

  8. for循环输出i为同一值的问题

    使用闭包将变量i的值保护起来. //sava1:加一层闭包,i以函数参数形式传递给内层函数 for( var i=0; i<ps.length; i++ ) { (function(arg){ ...

  9. python之文件读写操作(r/r+/rb/w/w+/wb/a/a+/ab)的作用

    'r':只读.该文件必须已存在. 'r+':可读可写.该文件必须已存在,写为追加在文件内容末尾. 'rb':表示以二进制方式读取文件.该文件必须已存在. 'w':只写.打开即默认创建一个新文件,如果文 ...

  10. CAS (Compare and Swap)

    synchronized是悲观锁 注意:实现了CAS的有原子类(AtomicInteger,AtomicLong,等等原子类) CAS 是乐观锁,一种高效实现线程安全性的方法 1.支持原子更新操作,适 ...