题意很明确,就是求最小生成树的个数……
专攻图论也有段时间了,求个最小生成树和判唯一,以及其他的一些应用都还算比较熟练了,但今天这道题,,,真给跪了,,,觉得自己需要补充大量的图论的定理啊什么的。
废话少说,,做出来这题参考了这篇题解【矩阵树定理 + kruskal】http://blog.youkuaiyun.com/jarily/article/details/8902402
当时做的时候都打算用费用流了,然而构图半天并没有做出来。。。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 505;
const int maxm = 5005;
struct Edge{
int u,v,cost;
bool operator < (const Edge &z) const {
return cost < z.cost;
}
}edge[maxm];
int n,m,mod;
int par[maxn],fa[maxn];
vector<int> V[maxn];
ll C[maxn][maxn],D[maxn][maxn];
bool vis[maxn];
void init_union(){
memset(D,0,sizeof(D));
memset(vis,0,sizeof(vis));
memset(par,-1,sizeof(par));
memset(fa,-1,sizeof(fa));
}
int find(int x,int f[]){
while(f[x] >= 0) x = f[x]; return x;
}
ll det(int len){
ll ans=1;
for(int i=0; i<len; i++)
{
for(int j=i+1; j<len; j++)
while(C[i][j]!=0)
{
ll t=C[i][i]/C[i][j];
for(int k=0; k<len; k++)
C[k][i]=(C[k][i]-(t*C[k][j])%mod)%mod;
ll temp;
for(int k=0; k<len; k++)
{
temp=C[k][i];
C[k][i]=C[k][j];
C[k][j]=temp;
}
ans=-ans;
}
if(C[i][i]==0)
return 0;
}
for(int i=0; i<len; i++)
ans=(ans*C[i][i]) % mod;
//printf("!!!!!!!\n");
//cout<<ans<<endl;
return (ans + mod) % mod;
}
void solve(){
sort(edge,edge+m);
init_union();
int cur = -1;
ll res = 1;
int u,v;
for(int k=0;k<=m;k++){
if(k == m || cur != edge[k].cost){
for(int i=1;i<=n;i++){
if(vis[i]){
vis[i] = false;
u = find(i,fa);
V[u].push_back(i);
}
}
for(int i=1;i<=n;i++){
int len = V[i].size();
if(len > 1){
for(int p=0;p<len;p++){
for(int q=0;q<len;q++) C[p][q] = 0;
}
for(int p=0;p<len;p++){
for(int q=p+1;q<len;q++){
u = V[i][p];
v = V[i][q];
C[p][q] -= D[u][v];
C[q][p] = C[p][q];
C[p][p] += D[u][v];
C[q][q] += D[u][v];
}
}
res = (res*det(len-1)) % mod;
for(int p=0;p<len;p++) if(V[i][p] != i) par[V[i][p]] = i;
}
V[i].clear();
}
//for(int i=1;i<=n;i++){
//if(i != find(i,par)) fa[i] = par[i] = find(i,par);
//}
if(k == m) break;
cur = edge[k].cost;
}
u = find(edge[k].u,par);
v = find(edge[k].v,par);
if(u == v) continue;
D[u][v]++;D[v][u]++;
vis[u] = vis[v] = true;
u = find(u,fa);v = find(v,fa);
if(u != v) fa[u] = v;
}
int cnt = 0;
for(int i=1;i<=n;i++) if(par[i] == -1) cnt++;
printf("%lld\n",(cnt != 1 || m == 0) ? 0 : res);
}
int main(){
while(~scanf("%d%d%d",&n,&m,&mod)){
if(n + m + mod == 0) break;
for(int i=0;i<m;i++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].cost);
solve();
}
return 0;
}