bzoj1016:[JSOI2008]最小生成树计数
思路:模拟kruskal的过程,可以发现对于所有权值相同的边,有很多种选择的方案,而且权值不同的边并不会相互影响,因为先考虑权值较小的边,权值比当前权值大的边显然不在考虑范围之内,而权值比当前权值小的边所组成的连通块已经经过缩点变成一个点了,因此处理权值相同的所有边可以看成是一个阶段,最后的答案也就是所有阶段的答案的乘积(乘法原理)。
那么如何来处理权值相同的方案数呢,同样还是考虑kruskal的过程,因为权值相同的边可能会组成很多个连通块,且连通块之间互不影响,因此只考虑单个连通块即可(还是乘法原理),如果一条边所连接的两个点不在一个连通块内,那么就把这条边算进答案,那么对于一个连通块kruskal的过程显然要让所有点连通,且所选的边恰好构成了一棵树,那么这样问题就转化成了如何求生成树的数量,利用matrix-tree定理,用高斯消元求解kirchhoff矩阵即可。
还有最后不要忘了判图中没有最小生成树的情况(图不连通)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxm 1005
#define maxn 105
#define mod 31011 int n,m,cnt,ans=1;
int fa[maxn],pos[maxn];
int K[maxn][maxn];
bool vis[maxn]; vector<int> v[maxn]; struct edge{
int from,to,val;
bool operator <(const edge &a)const{return val<a.val;}
}e[maxm]; inline int read(){
int x=0;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
} int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} int gauss(){
int t,n=cnt-1,ans=1,f=1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
K[i][j]%=mod;
for (int i=1;i<n;i++){
for (t=i;t<=n;t++) if (K[t][i]) break;if (t>n) return 0;
if (t!=i){for (int j=1;j<=n;j++) swap(K[i][j],K[t][j]);f=-f;}
for (int j=i+1;j<=n;j++)
for (;K[j][i];){
int t=K[i][i]/K[j][i];
for (int k=i;k<=n;k++) K[i][k]=(K[i][k]-t*K[j][k])%mod;
for (int k=i;k<=n;k++) swap(K[i][k],K[j][k]);
f=-f;
}
}
for (int i=1;i<=n;i++) ans=1ll*ans*K[i][i]%mod;
return ans*f;
} void dfs(int x,int num){
K[num][num]=v[x].size(),pos[x]=num;
for (unsigned int i=0;i<v[x].size();i++){
vis[v[x][i]]=0;
if (!pos[v[x][i]]) pos[v[x][i]]=++cnt,K[num][pos[v[x][i]]]--,dfs(v[x][i],cnt);
else K[num][pos[v[x][i]]]--;
}
} int main(){
n=read(),m=read();
for (int i=1;i<=m;i++) e[i].from=read(),e[i].to=read(),e[i].val=read();
for (int i=1;i<=n;i++) fa[i]=i;
sort(e+1,e+m+1);
for (int i=1;i<=m+1;i++){
int ck=find(1);
for (int j=2;j<=n;j++) if (find(j)!=ck){ck=0;break;}
if (ck) break;
int x=find(e[i].from),y=find(e[i].to);
if (x!=y) vis[x]=1,vis[y]=1,v[x].push_back(y),v[y].push_back(x);
if (e[i].val!=e[i+1].val){
for (int j=1;j<=n;j++)
if (vis[j]){
for (int a=1;a<=cnt;a++)
for (int b=1;b<=cnt;b++)
K[a][b]=0;
memset(pos,0,sizeof(pos));
vis[j]=0,cnt=1,dfs(j,cnt);
ans=1ll*ans*gauss()%mod;
}
for (int j=1;j<=n;j++){
for (unsigned int k=0;k<v[j].size();k++){
int x=find(j),y=find(v[j][k]);
if (x!=y) fa[x]=y;
}
v[j].clear();
}
}
}
int check=find(1);
for (int i=2;i<=n;i++) if (find(i)!=check){check=0;break;}
printf("%d\n",check?ans:0);
return 0;
}
bzoj1016:[JSOI2008]最小生成树计数的更多相关文章
- bzoj1016 [JSOI2008]最小生成树计数
1016: [JSOI2008]最小生成树计数 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3517 Solved: 1396[Submit][St ...
- bzoj1016: [JSOI2008]最小生成树计数(kruskal+dfs)
1016: [JSOI2008]最小生成树计数 题目:传送门 题解: 神题神题%%% 据说最小生成树有两个神奇的定理: 1.权值相等的边在不同方案数中边数相等 就是说如果一种方案中权值为1的边有n条 ...
- BZOJ1016:[JSOI2008]最小生成树计数(最小生成树,DFS)
Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的 ...
- [bzoj1016][JSOI2008]最小生成树计数 (Kruskal + Matrix Tree 定理)
Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的 ...
- 【Matrix-tree定理】【并查集】【kruscal算法】bzoj1016 [JSOI2008]最小生成树计数
题意:求一个图的最小生成树个数. 矩阵树定理:一张无向图的生成树个数 = (度数矩阵 - 邻接矩阵)的任意一个n-1主子式的值. 度数矩阵除了对角线上D[i][i]为i的度数(不计自环)外,其他位置是 ...
- [BZOJ1016][JSOI2008]最小生成树计数(结论题)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1016 分析: 首先有个性质:如果边集E.E'都可以表示一个图G的最小生成树(当然E和E ...
- [BZOJ1016] [JSOI2008] 最小生成树计数 (Kruskal)
Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的 ...
- 【最小生成树】BZOJ1016: [JSOI2008]最小生成树计数
Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的 ...
- 2018.09.24 bzoj1016: [JSOI2008]最小生成树计数(并查集+搜索)
传送门 正解是并查集+矩阵树定理. 但由于数据范围小搜索也可以过. 我们需要知道最小生成树的两个性质: 不同的最小生成树中,每种权值的边出现的个数是确定的 不同的生成树中,某一种权值的边连接完成后,形 ...
- [BZOJ1016][JSOI2008]最小生成树计数 最小生成树 搜索
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1016 做这道题之前需要知道一些结论,同一个图的最小生成树中相同权值的边的个数是不会变的,如 ...
随机推荐
- SQL 存储过程(学生,课程表,选修表)
SQL 存储过程(学生,课程表,选修表) 一.存储过程的分类 在SQL Server中存储过程分过两类: 1)系统存储过程("sp_"作为前缀) 2)用户自定义存储过程 二.创建和 ...
- Codeforces Round #268 (Div. 1) A. 24 Game 构造
A. 24 Game Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/468/problem/A D ...
- UITableViewCell 高度自适应
UITableViewCell 高度自适应一直是我们做动态Cell高度时遇到的最烦躁的问题,Cell动态高度计算可以去看看sunny的这篇文章介绍,今天主要和大家分享下我在使用systemLayout ...
- ios的NSMutableString用法
版权声明:本文为博主原创文章,未经博主允许不得转载. 详见代码: // // main.m // Foundation5-NSMutableString // // Created by mj ...
- 几种sap增强的查找方法
***方法一**************************************** 通过SE30,运行TCODE后,点Evaluate后,查看运行时间分析评估:命中清单. 找以“exit”开 ...
- 面试题总结之JAVA
JAVA 1. what is thread safe? 线程安全就是说多线程访问同一代码,不会产生不确定的结果.编写线程安全的代码是低依靠线程同步.线程安全: 在多线程中使用时,不用自已做同步处理线 ...
- Shell脚本文件操作
Linux Shell http://baike.baidu.com/link?url=2LxUhKzlh5xBUgQrS0JEc61xi761nvCS7SHJsa1U1SkVbw3CC869AoUC ...
- C#_Ajax_分页
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MvcTe ...
- Linux 学习笔记 基本的bash shell命令
Linux 文件系统 Linux讲文件存储在单个目录结构(虚拟目录)中,虚拟目录包含了安装在PC上的所有存储设备的文件路径. Linux虚拟目录中比较复杂的部分是它如何来协调管理各个存储设备.Linu ...
- Java设计模式10:设计模式之 值对象
1. 场景和问题: 在Java程序中,需要在对象之间交互大量的数据,比如要为方法传入参数,也要获取方法的返回值,请问如何能更好的进行数据的交互? 2. 解决方案: 值对象 3. 值对象的本质 ...