zoukankan      html  css  js  c++  java
  • 【BZOJ】1016: [JSOI2008]最小生成树计数

    题解

    考虑kruskal
    我们都是从边权最小的边开始取,然后连在一起

    那我们选出边权最小的一堆边,然后这个图就分成了很多联通块,把每个联通块内部用矩阵树定理算一下生成树个数,再把联通块缩成一个大点,重复取下一个边权的边进行操作

    好想然而不是很好写= =写起来感觉有点麻烦

    模数非质数,用long double水一下过掉了

    代码

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <cmath>
    #include <bitset>
    #include <queue>
    #define enter putchar('
    ')
    #define space putchar(' ')
    //#define ivorysi
    #define pb push_back
    #define mo 974711
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define MAXN 200005
    #define eps 1e-12
    using namespace std;
    typedef long long int64;
    typedef long double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 - '0' + c;
    	c = getchar();
        }
        res = res * f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    int N,M;
    struct node {
        int u,v,c;
        friend bool operator < (const node &a,const node &b) {
    	return a.c < b.c;
        }
    }E[1005];
    int fa[105],id[105],f[105][105],L[105],tot,D[105];
    bool vis[105];
    db g[105][105];
    int64 ans = 1;
    int getfa(int x) {
        return x == fa[x] ? x : fa[x] = getfa(fa[x]);
    } 
    db Guass(int n) {
        db res = 1;
        for(int i = 2 ; i <= n ; ++i) {
    	int l = i;
    	for(int j = i + 1 ; j <= n ; ++j) {
    	    if(fabs(g[j][i]) > fabs(g[l][i])) l = j;
    	}
    	if(i != l) {
    	    res = -res;
    	    for(int j = i ; j <= n ; ++j) {
    		swap(g[i][j],g[l][j]);
    	    }
    	}
    	if(fabs(g[i][i]) == 0) return 0;
    	for(int j = i + 1 ; j <= n ; ++j) {
    	    db t = g[j][i] / g[i][i];
    	    for(int k = i ; k <= n ; ++k) {
    		g[j][k] -= g[i][k] * t;
    	    }
    	}
        }
        for(int k = 2 ; k <= n ; ++k) {
    	res = res * g[k][k];
        }
        return res;
    }
    void dfs(int u,int n) {
        vis[u] = 1;
        L[++tot] = u;
        D[u] = tot;
        for(int i = 1 ; i <= n ; ++i) {
    	if(f[u][i]) {
    	    if(!vis[i]) dfs(i,n);
    	}
        }
    }
    void Process(int l,int r) {
        memset(id,0,sizeof(id));
        memset(f,0,sizeof(f));
        memset(vis,0,sizeof(vis));
        int cnt = 0;
        for(int i = 1 ; i <= N ; ++i) {
    	if(!id[getfa(i)]) {
    	    id[getfa(i)] = ++cnt;
    	}
        }
        for(int i = l ; i <= r ; ++i) {
    	int s = getfa(E[i].u),t = getfa(E[i].v);
    	if(s == t) continue;
    	f[id[s]][id[t]]++; f[id[t]][id[s]]++;
        }
        for(int i = 1 ; i <= cnt ; ++i) {
    	if(!vis[i]) {
    	    tot = 0;
    	    dfs(i,cnt);
    	    if(tot == 1) continue;
    	    memset(g,0,sizeof(g));
    	    for(int j = 1 ; j <= tot ; ++j) {
    		int u = L[j];
    		for(int k = 1 ; k <= cnt ; ++k) {
    		    if(f[u][k]) {
    			g[j][j] += f[u][k];
    			g[j][D[k]] -= f[u][k];
    		    }
    		}
    	    }
    	    ans = ans * ((int64)(Guass(tot) + 0.5) % 31011) % 31011;
    	}
        }
        for(int i = l ; i <= r ; ++i) {
    	fa[getfa(E[i].v)] = getfa(E[i].u);
        }
    }
    void Solve() {
        read(N);read(M);
        for(int i = 1 ; i <= N ; ++i) fa[i] = i;
        int u,v,c;
        for(int i = 1 ; i <= M ; ++i) {
    	read(E[i].u);read(E[i].v);read(E[i].c);
    	fa[getfa(E[i].u)] = getfa(E[i].v);
        }
        for(int i = 2 ; i <= N ; ++i) {
    	if(getfa(i) != getfa(i - 1)) {
    	    puts("0");
    	    return;
    	}
        }
        for(int i = 1 ; i <= N ; ++i) fa[i] = i;
        sort(E + 1,E + M + 1);
        v = 0;int st = 0;
        bool flag = 0;
        for(int i = 1 ; i <= M ; ++i) {
    	if(E[i].c != v) {
    	    if(st != 0) Process(st,i - 1);
    	    st = i;
    	    v = E[i].c;
    	    flag = 1;
    	    for(int j = 2 ; j <= N ; ++j) {
    		if(getfa(j) != getfa(j - 1)) {flag = 0;break;}
    	    }
    	    if(flag) break;
    	}
        }
        if(!flag) Process(st,M);
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    
  • 相关阅读:
    教程:如何手动安装Xamarin与Xamarin for VisualStudio
    安装matplotlib
    pycharm中文专业版安装使用
    在win7下安装PowerShell 5.0遇到的坑
    1997-2017
    系统界面截图
    组态与非组态结合的LT
    opencv mat转qimage
    QTableWidget 样式文件
    hiredis window 源码编译
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9211769.html
Copyright © 2011-2022 走看看