【BZOJ】1016: [JSOI2008]最小生成树计数
2018-06-22 08:55
489 查看
题解
考虑kruskal
我们都是从边权最小的边开始取,然后连在一起
那我们选出边权最小的一堆边,然后这个图就分成了很多联通块,把每个联通块内部用矩阵树定理算一下生成树个数,再把联通块缩成一个大点,重复取下一个边权的边进行操作
好想然而不是很好写= =写起来感觉有点麻烦
模数非质数,用long double水一下过掉了
代码
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <vector> #include <set> #include <cmath> #include <bitset> #include <queue> #define enter putchar('\n') #define space putchar(' ') //#define ivorysi #define pb push_back #define mo 974711 #define pii pair<int,int> #define mp make_pair #define fi first #define se second #define MAXN 200005 #define eps 1e-12 using namespace std; typedef long long int64; typedef long double db; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 - '0' + c; c = getchar(); } res = res * f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) out(x / 10); putchar('0' + x % 10); } int N,M; struct node { int u,v,c; friend bool operator < (const node &a,const node &b) { return a.c < b.c; } }E[1005]; int fa[105],id[105],f[105][105],L[105],tot,D[105]; bool vis[105]; db g[105][105]; int64 ans = 1; int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); } db Guass(int n) { db res = 1; for(int i = 2 ; i <= n ; ++i) { int l = i; for(int j = i + 1 ; j <= n ; ++j) { if(fabs(g[j][i]) > fabs(g[l][i])) l = j; } if(i != l) { res = -res; for(int j = i ; j <= n ; ++j) { swap(g[i][j],g[l][j]); } } if(fabs(g[i][i]) == 0) return 0; for(int j = i + 1 ; j <= n ; ++j) { db t = g[j][i] / g[i][i]; for(int k = i ; k <= n ; ++k) { g[j][k] -= g[i][k] * t; } } } for(int k = 2 ; k <= n ; ++k) { res = res * g[k][k]; } return res; } void dfs(int u,int n) { vis[u] = 1; L[++tot] = u; D[u] = tot; for(int i = 1 ; i <= n ; ++i) { if(f[u][i]) { if(!vis[i]) dfs(i,n); } } } void Process(int l,int r) { memset(id,0,sizeof(id)); memset(f,0,sizeof(f)); memset(vis,0,sizeof(vis)); int cnt = 0; for(int i = 1 ; i <= N ; ++i) { if(!id[getfa(i)]) { id[getfa(i)] = ++cnt; } } for(int i = l ; i <= r ; ++i) { int s = getfa(E[i].u),t = getfa(E[i].v); if(s == t) continue; f[id[s]][id[t]]++; f[id[t]][id[s]]++; } for(int i = 1 ; i <= cnt ; ++i) { if(!vis[i]) { tot = 0; dfs(i,cnt); if(tot == 1) continue; memset(g,0,sizeof(g)); for(int j = 1 ; j <= tot ; ++j) { int u = L[j]; for(int k = 1 ; k <= cnt ; ++k) { if(f[u][k]) { g[j][j] += f[u][k]; g[j][D[k]] -= f[u][k]; } } } ans = ans * ((int64)(Guass(tot) + 0.5) % 31011) % 31011; } } for(int i = l ; i <= r ; ++i) { fa[getfa(E[i].v)] = getfa(E[i].u); } } void Solve() { read(N);read(M); for(int i = 1 ; i <= N ; ++i) fa[i] = i; int u,v,c; for(int i = 1 ; i <= M ; ++i) { read(E[i].u);read(E[i].v);read(E[i].c); fa[getfa(E[i].u)] = getfa(E[i].v); } for(int i = 2 ; i <= N ; ++i) { if(getfa(i) != getfa(i - 1)) { puts("0"); return; } } for(int i = 1 ; i <= N ; ++i) fa[i] = i; sort(E + 1,E + M + 1); v = 0;int st = 0; bool flag = 0; for(int i = 1 ; i <= M ; ++i) { if(E[i].c != v) { if(st != 0) Process(st,i - 1); st = i; v = E[i].c; flag = 1; for(int j = 2 ; j <= N ; ++j) { if(getfa(j) != getfa(j - 1)) {flag = 0;break;} } if(flag) break; } } if(!flag) Process(st,M); out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }
相关文章推荐
- BZOJ1016 JSOI2008 最小生成树计数
- BZOJ 1016 [JSOI2008]最小生成树计数 dfs
- 【bzoj1016】[JSOI2008]最小生成树计数
- MST——BZOJ1016 [JSOI2008]最小生成树计数
- bzoj1016 [JSOI2008]最小生成树计数
- bzoj 1016: [JSOI2008]最小生成树计数
- BZOJ 1016 [JSOI2008]最小生成树计数 ——Matrix-Tree定理
- 【BZOJ1016】【JSOI2008】最小生成树计数 kruskal+dfs
- bzoj 1016: [JSOI2008]最小生成树计数
- [BZOJ]1016: [JSOI2008]最小生成树计数
- BZOJ 1016 JSOI 2008 最小生成树计数 Kruskal+搜索
- 【BZOJ 1016】 1016: [JSOI2008]最小生成树计数 (DFS|矩阵树定理)
- bzoj1016: [JSOI2008]最小生成树计数(kruskal+dfs)
- 【Kruskal+dfs】BZOJ1016- [JSOI2008]最小生成树计数
- [BZOJ]1016 JSOI2008 最小生成树计数
- 【BZOJ】1016: [JSOI2008]最小生成树计数
- 【kruskal】【dfs】【JSOI 2008】【bzoj 1016】最小生成树计数
- BZOJ 1016 [JSOI2008]最小生成树计数
- [BZOJ1016][JSOI2008]最小生成树计数(Kruskal+计数)
- 【BZOJ 1016】【JSOI 2008】最小生成树计数