题意:
给定一个无向带权图,要求求出这个图最小生成树的个数。
思路:
如果不连通的话就输出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;
}