题意:
给定一个无向带权图,要求求出这个图最小生成树的个数。
思路:
如果不连通的话就输出0。如果是无权图,直接用矩阵树定理就可以。
对于带全图, 先把所有边排序, 然后从小到大考虑边权, 对于一组边权相同的边, 根据kruskal, 加入了这些边之后, 图的连通性是确定的,
也就是哪些点跟哪些点是不是连通是确定的, 但是选边的方案是不一样的, 于是对选了这组边之后在同一个联通块的边, 用按照无向图来处理, 注意, 本来就已经在同一个连通块的边不能算进去。然后各个联通块的方案数乘起来,最后, 所有边权的方案数都乘起来就是答案。
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; #define mxn 120 #define mxe 1020 #define PB push_back #define LL long long struct edge { int u, v, c; void input() { scanf("%d%d%d", &u, &v, &c); } bool operator < (const edge &b) const { return c < b.c; } }e[mxe]; int n, m, p; LL a[mxn][mxn]; int fa[mxn], tf[mxn]; int R(int t[], int x) { if(t[x] != x) t[x] = R(t, t[x]); return t[x]; } void un(int t[], int u, int v) { t[R(t, u)] = R(t, v); } LL gauss(int N) { // printf("N %d\n", N); for(int i = 0; i < N; ++i) { // printf(" .."); for(int j = 0; j < N; ++j) { // printf("%I64d ", a[i][j]); a[i][j] = (a[i][j] % p + p) % p; } // puts(""); } LL ret = 1; for(int i = 0; i < N; ++i) { int u = i; while(u < N && a[u][i] == 0) ++u; if(u >= N) { // puts(">>"); return 0; } if(u != i) { for(int j = i; j < N; ++j) swap(a[u][j], a[i][j]); ret = (p - ret) % p; } for(int k = i + 1; k < N; ++k) { while(a[k][i]) { LL t = a[i][i] / a[k][i]; for(int j = i; j < N; ++j) { a[i][j] = ((a[i][j] - a[k][j] * t) % p + p) % p; swap(a[i][j], a[k][j]); } ret = (-ret + p) % p; } } ret = ret * a[i][i] % p; } return ret; } int main(){ // freopen("tt.txt", "r", stdin); while(scanf("%d%d%d", &n, &m, &p) && n) { for(int i = 1; i <= m; ++i) { e[i].input(); } if(p == 1) { puts("0"); continue; } sort(e + 1, e + m + 1); LL ans = 1; for(int i = 1; i <= n; ++i) fa[i] = i; for(int i = 1; i <= m;) { int j = i; while(j <= m && e[i].c == e[j].c) ++j; memcpy(tf, fa, sizeof tf); for(int k = i; k < j; ++k) { int u = e[k].u, v = e[k].v; un(tf, u, v); } vector<int> g[mxn]; for(int k = i; k < j; ++k) { int u = e[k].u; g[R(tf, u)].push_back(k); } vector<int> x; for(int k = 1; k <= n; ++k) { x.clear(); if(g[k].size() == 0) continue; for(int s = 0; s < g[k].size(); ++s) { int u = e[g[k][s]].u, v = e[g[k][s]].v; u = R(fa, u), v = R(fa, v); if(u == v) continue; x.PB(u), x.PB(v); } sort(x.begin(), x.end()); x.erase(unique(x.begin(), x.end()), x.end()); int cnt = x.size(); if(cnt <= 1) continue; for(int i = 0; i < cnt; ++i) for(int j = 0; j < cnt; ++j) a[i][j] = 0; for(int s = 0; s < g[k].size(); ++s) { int u = e[g[k][s]].u, v = e[g[k][s]].v; u = R(fa, u), v = R(fa, v); if(u == v) continue; u = lower_bound(x.begin(), x.end(), u) - x.begin(); v = lower_bound(x.begin(), x.end(), v) - x.begin(); // puts("+++"); a[u][u]++, a[v][v]++; a[u][v]--, a[v][u]--; } ans = ans * gauss(cnt - 1) % p; } for(int k = i; k < j; ++k) { int u = e[k].u, v = e[k].v; un(fa, u, v); } i = j; } int c = -1; for(int i = 1; i <= n; ++i) { if(c == -1) c = R(fa, i); else if(c != R(fa, i)) { c = -2; break; } } if(c == -2) { puts("0"); } else printf("%I64d\n", ans); } return 0; }