hdu 4408 Minimum Spanning Tree 最小生成树计数

题意:

给定一个无向带权图,要求求出这个图最小生成树的个数。

思路:

如果不连通的话就输出0。

如果是无权图,直接用矩阵树定理就可以。

对于带全图, 先把所有边排序, 然后从小到大考虑边权, 对于一组边权相同的边, 根据kruskal, 加入了这些边之后, 图的连通性是确定的,

也就是哪些点跟哪些点是不是连通是确定的, 但是选边的方案是不一样的, 于是对选了这组边之后在同一个联通块的边, 用按照无向图来处理, 注意, 本来就已经在同一个连通块的边不能算进去。然后各个联通块的方案数乘起来,最后, 所有边权的方案数都乘起来就是答案。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

#define mxn 120
#define mxe 1020
#define PB push_back
#define LL long long

struct edge {
    int u, v, c;
    void input() {
        scanf("%d%d%d", &u, &v, &c);
    }
    bool operator < (const edge &b) const {
        return c < b.c;
    }
}e[mxe];
int n, m, p;

LL a[mxn][mxn];
int fa[mxn], tf[mxn];
int R(int t[], int x) {
    if(t[x] != x)
        t[x] = R(t, t[x]);
    return t[x];
}
void un(int t[], int u, int v) {
    t[R(t, u)] = R(t, v);
}
LL gauss(int N) {
  //  printf("N        %d\n", N);
    for(int i = 0; i < N; ++i) {
     //   printf("    ..");
        for(int j = 0; j < N; ++j) {
         //   printf("%I64d ", a[i][j]);
            a[i][j] = (a[i][j] % p + p) % p;
        }
     //   puts("");
    }
    LL ret = 1;
    for(int i = 0; i < N; ++i) {
        int u = i;
        while(u < N && a[u][i] == 0) ++u;
        if(u >= N) {
        //    puts(">>");
            return 0;
        }
        if(u != i) {
            for(int j = i; j < N; ++j)
                swap(a[u][j], a[i][j]);
            ret = (p - ret) % p;
        }
        for(int k = i + 1; k < N; ++k) {
            while(a[k][i]) {
                LL t = a[i][i] / a[k][i];
                for(int j = i; j < N; ++j) {
                    a[i][j] = ((a[i][j] - a[k][j] * t) % p + p) % p;
                    swap(a[i][j], a[k][j]);
                }
                ret = (-ret + p) % p;
            }
        }
        ret = ret * a[i][i] % p;
    }
    return ret;
}
int main(){
//	freopen("tt.txt", "r", stdin);
    while(scanf("%d%d%d", &n, &m, &p) && n) {
        for(int i = 1; i <= m; ++i) {
            e[i].input();
        }
        if(p == 1) {
            puts("0");
            continue;
        }
        sort(e + 1, e + m + 1);
        LL ans = 1;
        for(int i = 1; i <= n; ++i) fa[i] = i;
        for(int i = 1; i <= m;) {
            int j = i;
            while(j <= m && e[i].c == e[j].c) ++j;
            memcpy(tf, fa, sizeof tf);
            for(int k = i; k < j; ++k) {
                int u = e[k].u, v = e[k].v;
                un(tf, u, v);
            }
            vector<int> g[mxn];
            for(int k = i; k < j; ++k) {
                int u = e[k].u;
                g[R(tf, u)].push_back(k);
            }
            vector<int> x;
            for(int k = 1; k <= n; ++k) {
				x.clear();
                if(g[k].size() == 0) continue;
                for(int s = 0; s < g[k].size(); ++s) {
                    int u = e[g[k][s]].u, v = e[g[k][s]].v;
                    u = R(fa, u), v = R(fa, v);
                    if(u == v) continue;
                    x.PB(u), x.PB(v);
                }
                sort(x.begin(), x.end());
                x.erase(unique(x.begin(), x.end()), x.end());
                int cnt = x.size();
                if(cnt <= 1) continue;
                for(int i = 0; i < cnt; ++i)
                    for(int j = 0; j < cnt; ++j)
                        a[i][j] = 0;
                for(int s = 0; s < g[k].size(); ++s) {
                    int u = e[g[k][s]].u, v = e[g[k][s]].v;
                    u = R(fa, u), v = R(fa, v);
                    if(u == v) continue;
                    u = lower_bound(x.begin(), x.end(), u) - x.begin();
                    v = lower_bound(x.begin(), x.end(), v) - x.begin();
               //     puts("+++");
                    a[u][u]++, a[v][v]++;
                    a[u][v]--, a[v][u]--;
                }
                ans = ans * gauss(cnt - 1) % p;
            }
            for(int k = i; k < j; ++k) {
                int u = e[k].u, v = e[k].v;
                un(fa, u, v);
            }
            i = j;
        }
        int c = -1;
        for(int i = 1; i <= n; ++i) {
            if(c == -1)
                c = R(fa, i);
            else if(c != R(fa, i)) {
                c = -2;
                break;
            }
        }
        if(c == -2) {
            puts("0");
        }
        else
            printf("%I64d\n", ans);
    }
    return 0;

}


你可能感兴趣的:(hdu 4408 Minimum Spanning Tree 最小生成树计数)