【JSOI2008】【BZOJ1016】最小生成树计数
来源:互联网 发布:计算机编程培训网校 编辑:程序博客网 时间:2024/04/28 02:10
我就爱写矩阵树定理!!!
就不写暴力!!!
1016: [JSOI2008]最小生成树计数
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 3584 Solved: 1429
[Submit][Status][Discuss]
Description
现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。
Input
第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。
Output
输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。
Sample Input
4 6
1 2 1
1 3 1
1 4 1
2 3 2
2 4 1
3 4 1
Sample Output
8
HINT
Source
边权把所有边排序
边权相同的边构成连通块
每个连通块做一遍矩阵树
答案相乘
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define P 31011#define MAXN 110#define MAXINT 0x7fffffffusing namespace std;int C[MAXN][MAXN],D[MAXN][MAXN],A[MAXN][MAXN];int block[MAXN][MAXN],top[MAXN];long long ans=1;int n,m;bool vis[MAXN];struct Set{ int f[MAXN]; int find(int x) { if (f[x]==x) return x; return f[x]=find(f[x]); } void Union(int x,int y) { int a=find(x),b=find(y); f[b]=a; }}s1,s2;//对每个连通块用s2,总体用s1 struct edge{ int u,v,w; bool operator <(const edge& a)const { return w<a.w; }}e[MAXN*10];void in(int &x){ char ch=getchar();x=0; while (!(ch>='0'&&ch<='9')) ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();}int calc(int size){ int ret=1; for (int i=1;i<=size;i++) for (int j=1;j<=size;j++) C[i][j]=(C[i][j]+P)%P; for (int i=1;i<=size;i++) { for (int j=i+1;j<=size;j++) { int a=C[i][i],b=C[j][i]; while (b) { int t=a/b;a%=b;swap(a,b); for (int k=i;k<=size;k++) C[i][k]=(C[i][k]-C[j][k]*t)%P; for (int k=i;k<=size;k++) swap(C[i][k],C[j][k]); ret=-ret; } } if (!C[i][i]) return 0; ret*=C[i][i];ret%=P; } return (ret+P)%P;}void print(){ for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) cout<<C[i][j]<<' '; cout<<endl; } }void Print(){ for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) cout<<A[i][j]<<' '; cout<<endl; } cout<<endl;}int main(){ in(n);in(m); if (m<n-1) { cout<<0<<endl; return 0; } for (int i=1;i<=m;i++) in(e[i].u),in(e[i].v),in(e[i].w); for (int i=1;i<=n;i++) s1.f[i]=s2.f[i]=i; sort(e+1,e+m+1); int t=-MAXINT; for (int i=1;i<=m+1;i++) { if (e[i].w!=t||i>m)//边权不同,计算行列式值,进入下一个连通块 { for (int j=1;j<=n;j++) if (vis[j]) { int F=s2.find(j); block[F][++top[F]]=j; vis[j]=0; } for (int j=1;j<=n;j++) if (top[j]>1) { memset(C,0,sizeof(C)); for (int k=1;k<=top[j];k++)//对连通块构建矩阵 for (int l=k+1;l<=top[j];l++) { int a=block[j][k],b=block[j][l]; C[k][l]=(C[l][k]-=A[a][b]); C[k][k]+=A[a][b];C[l][l]+=A[a][b]; } ans=(ans%P*calc(top[j]-1))%P; for (int k=1;k<=top[j];k++) s1.f[block[j][k]]=j; } for (int j=1;j<=n;j++) { s1.f[j]=s2.f[j]=s1.find(j); top[j]=0;memset(block[j],0,sizeof(block[j])); } if (i>m) break; t=e[i].w; } int x=s1.find(e[i].u),y=s1.find(e[i].v); if (x==y) continue; vis[x]=vis[y]=1; s2.Union(x,y); D[x][x]++;D[y][y]++;A[x][y]++;A[y][x]++; } cout<<ans<<endl;}
1 0
- 【BZOJ1016】[JSOI2008]最小生成树计数
- BZOJ1016 [JSOI2008]最小生成树计数
- BZOJ1016 && JSOI2008] 最小生成树计数
- bzoj1016: [JSOI2008]最小生成树计数
- 【JSOI2008】【BZOJ1016】最小生成树计数
- jsoi2008最小生成树计数bzoj1016
- bzoj1016: [JSOI2008]最小生成树计数
- [BZOJ1016][JSOI2008]最小生成树计数
- BZOJ1016 [JSOI2008]最小生成树计数
- 【JSOI2008】 bzoj1016 最小生成树计数
- BZOJ1016: [JSOI2008]最小生成树计数 Kruskal
- 【bzoj1016】 JSOI2008—最小生成树计数
- bzoj1016: [JSOI2008]最小生成树计数
- 【bzoj1016】[JSOI2008]最小生成树计数
- [bzoj1016][JSOI2008]最小生成树计数
- BZOJ1016: [JSOI2008]最小生成树计数
- 【bzoj1016】[JSOI2008]最小生成树计数
- BZOJ1016 [JSOI2008]最小生成树计数
- flume采集的一些特性
- 苹果笔记本win7系统触摸板无法右键功能
- <button>标签与<form>标签对于创建按钮的区别
- sqlserver 已超过了锁请求超时时段 1222错误
- HashMap的数据结构
- 【JSOI2008】【BZOJ1016】最小生成树计数
- android stuio修改代码参考线和智能换行
- 最短路
- 【译】Android主题动态切换开源库Prism基本原理3-搭配Palette使用
- Java 之小数取整
- iOS——常用开发工具
- jsp简介
- Intellij IDEA 试用心得(Intellij初始设置)以及常用快捷键
- LINUX修改文件名rename