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 做这道题之前需要知道一些结论,同一个图的最小生成树中相同权值的边的个数是不会变的,如 ...
随机推荐
- 项目androidAnt编译打包Android项目
时间紧张,先记一笔,后续优化与完善. Ant编译打包Android项目 在Eclipse中对Android项目停止编译和打包如果项目比较大的话会比较慢,所以改为Ant工具来停止编译和打包 Ant环境配 ...
- Cocos2d-x 3.0心得(01)-图片载入与混合模式
近期開始用cocos2dx 3.0做东西,略有心(cao)得(dian),略微作下记录吧. v3.0相对v2.2来说,最引人注意的,应该是对触摸层级的优化.和lambda回调函数的引入(嗯嗯.不枉我改 ...
- Advanced Configuration Tricks
Advanced Configuration Tricks Configuration of zend-mvc applications happens in several steps: Initi ...
- Android(java)学习笔记128:使用proguard混淆android代码
1.当前是有些工具比如apktool,dextojar等是可以对我们android安装包进行反编译,获得源码的.为了减少被别人破解,导致源码泄露,程序被别人盗取代码,等等.我们需要对代码进行混淆,an ...
- 如何真正免费运营推广APP应用
随着移动终端的迅速普及,各类APP如雨后春笋般涌现出来,但是真正的运营成功的产品却寥寥无几. 从瓜分渠道资源到抢占用户的过程中,很多同行都明显的感觉到,渠道平台所带来的量日益减少,但是刊例价格却一再攀 ...
- opencv拼接相关1
这里面都是一些比较杂的东西,没什么实际意义.主要是为了,后面能跑一个程序: Stitcher: 抠细节: http://docs.opencv.org/2.4.2/modules/stitching/ ...
- C语言---翻译过程
c的实现中包括两种环境: 1.翻译环境(translation environment):源程序---->机器指令 2.执行环境(execution environment):执行机器指令 这两 ...
- 关于JDBC链接数据库的代码实现
/** * 快速入门 */ @Test public void demo1() { /** * * 1.加载驱动. * * 2.获得连接. * * 3.编写sql执行sql. * * 4.释放资源. ...
- 灯笼Lantern下载及使用教程
http://www.iyaxi.com/2015-11-17/732.html 最新科学上网QQ群群号:465166189点击链接加入群[翻越长城三群]:http://jq.qq.com/?_wv= ...
- Flash cs6 帧上的菱形原来是关键帧
假如需要删除这个关键帧,选中它,然后右键,"清除关键帧",相应的类型即可. 因为之前学了一点点Flash,没见过帧上面这个菱形图标,才知道是关键帧.