[Bzoj1016][JSOI2008]最小生成树计数
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1016
首先要知道最小生成树的性质:不管这个最小生成树如何构成,同样权值的边的个数是不变的。
所以讲每条边按权值排序,并记录最小生成树中该类权值的个数,然后爆搜。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 6e6 + 10; const int mod = 31011; struct node { int s, e, w; }q[maxn]; struct qujian { int l, r, val; }a[maxn]; int fa[maxn]; int Find(int x) { return x == fa[x] ? fa[x] : Find(fa[x]); } bool cmp(node a, node b) { return a.w < b.w; } int sum; void dfs(int x, int now, int k) { if (now == a[x].r + 1) { if (k == a[x].val) sum++; return; } int xx = Find(q[now].s); int yy = Find(q[now].e); if (xx != yy) { fa[xx] = yy; dfs(x, now + 1, k + 1); fa[xx] = xx, fa[yy] = yy; } dfs(x, now + 1, k); } int main() { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++)fa[i] = i; for (int i = 1; i <= m; i++) scanf("%d%d%d", &q[i].s, &q[i].e, &q[i].w); sort(q + 1, q + 1 + m, cmp); int cnt = 1, num = 0, ans = 1; for (int i = 1; i <= m; i++) { if (q[i].w != q[i - 1].w) { a[cnt++].r = i - 1; a[cnt].l = i; } int xx = Find(q[i].s); int yy = Find(q[i].e); if (xx != yy) { a[cnt].val++; fa[xx] = yy; num++; } } if (num != n - 1) { printf("0"); return 0; } a[cnt].r = m; for (int i = 1; i <= n; i++) fa[i] = i; for (int i = 1; i <= cnt; i++) { sum = 0; dfs(i, a[i].l, 0); ans = ans * sum % mod; for (int j = a[i].l; j <= a[i].r; j++) { int xx = Find(q[j].s); int yy = Find(q[j].e); if (xx != yy) fa[xx] = yy; } } printf("%d\n", ans); }