[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);
}

 

posted @ 2019-07-03 13:56  祈梦生  阅读(166)  评论(0编辑  收藏  举报