# [BZOJ 1016] [JSOI2008] 最小生成树计数 【DFS】

### 题目分析

1）同一种权值的边的个数相等

2）用Kruscal按照从小到大，处理完某一种权值的所有边后，图的连通性相等

### 代码

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>

using namespace std;

const int MaxN = 100 + 5, MaxM = 1000 + 5, Mod = 31011;

int n, m, Top, Sum, Cnt;
int f[MaxN], L[MaxM], R[MaxM], Num[MaxM];

typedef long long LL;
LL Ans;

struct Edge
{
int u, v, w;
} E[MaxM];

inline bool Cmp(Edge e1, Edge e2)
{
return e1.w < e2.w;
}

inline int Find(int x, int o)
{
int i, j, k;
j = x;
while (j != f[j]) j = f[j];
if (o == 1) return j;
i = x;
while (i != j)
{
k = i;
i = f[i];
f[k] = j;
}
return j;
}

void DFS(int Type, int x, int y)
{
if (x == R[Type] + 1)
{
if (y == Num[Type]) ++Cnt;
return;
}
int fx, fy;
fx = Find(E[x].u, 1); fy = Find(E[x].v, 1);
if (fx != fy)
{
f[fx] = fy;
DFS(Type, x + 1, y + 1);
f[fx] = fx;
}
DFS(Type, x + 1, y);
}

int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i)
scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
sort(E + 1, E + m + 1, Cmp);
Top = 0; Sum = 0;
int fx, fy;
for (int i = 1; i <= n; ++i) f[i] = i;
for (int i = 1; i <= m; ++i)
{
if (i == 1 || E[i].w != E[i - 1].w) L[++Top] = i;
R[Top] = i;
fx = Find(E[i].u, 0); fy = Find(E[i].v, 0);
if (fx != fy)
{
f[fx] = fy;
++Num[Top];
++Sum;
}
}
if (Sum != n - 1)
{
printf("0\n");
return 0;
}
for (int i = 1; i <= n; ++i) f[i] = i;
Ans = 1;
for (int i = 1; i <= Top; ++i)
{
if (Num[i] == 0) continue;
Cnt = 0;
DFS(i, L[i], 0);
Ans = Ans * (LL)Cnt % Mod;
for (int j = L[i]; j <= R[i]; ++j)
{
fx = Find(E[j].u, 0); fy = Find(E[j].v, 0);
if (fx != fy) f[fx] = fy;
}
}
printf("%d\n", (int)Ans);
return 0;
}


posted @ 2015-03-06 21:26  JoeFan  阅读(...)  评论(... 编辑 收藏