_bzoj1016 [JSOI2008]最小生成树计数【生成树】
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1016
其实原题不叫这个的,而且原题是有一个背景故事的。。。
首先,容易得知,一个最小生成树不管是什么样的,同一种长度的边出现的次数是一样的。而且由Kruscal的过程,若当前节点对整个图减少一个联通块有贡献,则加这条边,也就是说在比当前边短的边已经全部考虑完后,与当前边一样长的所有边对整个图的连通性的贡献是一样的。则,若最小生成树中与当前边一样长的边出现了x次,共有tot条,那么暴力枚举C(tot, x)次,若它们不构成环,则是合法的。最后对每种长度的边乘法原理一下就ok咯~
注意题目陷阱:原图有可能没有生成树,此时输出0!
#include <cstdio> #include <algorithm> #include <cstring> const int maxn = 105, maxm = 1005, mod = 31011; int n, m, fa[maxn], num[maxm], cnt, t_fa[15][maxn], idx, fu, fv, ans, t_ans; int head[maxm], to[maxm], next[maxm], lb, max_step; struct Edge { int u, v, ww, w; } a[maxm]; bool cmp(const Edge & aa, const Edge & ss) { return aa.ww < ss.ww; } int getfa(int * ff, int aa) { return ff[aa] == aa? aa: ff[aa] = getfa(ff, ff[aa]); } inline void ist(int aa, int ss) { to[lb] = ss; next[lb] = head[aa]; head[aa] = lb; ++lb; } void dfs(int step, int now) { if (step == max_step) { ++t_ans; return; } for (int j = next[now]; j != -1; j = next[j]) { fu = getfa(t_fa[step - 1], a[to[j]].u); fv = getfa(t_fa[step - 1], a[to[j]].v); if (fu == fv) { continue; } memcpy(t_fa[step], t_fa[step - 1], sizeof fa); t_fa[step][fu] = fv; dfs(step + 1, j); } } int main(void) { //freopen("in.txt", "r", stdin); memset(head, -1, sizeof head); memset(next, -1, sizeof next); scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) { fa[i] = i; } for (int i = 0; i < m; ++i) { scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].ww); } std::sort(a, a + m, cmp); a[0].w = 1; idx = 1; ist(1, 0); for (int i = 1; i < m; ++i) { if (a[i].ww == a[i - 1].ww) { a[i].w = idx; } else { a[i].w = ++idx; } ist(a[i].w, i); } memcpy(t_fa[0], fa, sizeof fa); for (int i = 0; i < m; ++i) { fu = getfa(fa, a[i].u); fv = getfa(fa, a[i].v); if (fu != fv) { fa[fu] = fv; ++num[a[i].w]; if (++cnt == n - 1) { break; } } } if (cnt < n - 1) { puts("0"); return 0; } memcpy(fa, t_fa[0], sizeof fa); ans = 1; for (int i = 1; i <= n; ++i) { fa[i] = i; } for (int i = 1; i <= idx; ++i) { if (!num[i]) { continue; } max_step = num[i]; t_ans = 0; for (int j = head[i]; j != -1; j = next[j]) { fu = getfa(fa, a[to[j]].u); fv = getfa(fa, a[to[j]].v); if (fu == fv) { continue; } memcpy(t_fa[0], fa, sizeof fa); t_fa[0][fu] = fv; dfs(1, j); } for (int j = head[i]; j != -1; j = next[j]) { fu = getfa(fa, a[to[j]].u); fv = getfa(fa, a[to[j]].v); if (fu != fv) { fa[fu] = fv; } } ans = ans * t_ans % mod; } printf("%d\n", ans); return 0; }