zoukankan      html  css  js  c++  java
  • BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )

    不同最小生成树中权值相同的边数量是一定的, 而且他们对连通性的贡献是一样的.对权值相同的边放在一起(至多10), 暴搜他们有多少种方案, 然后乘法原理。

    -------------------------------------------------------------------------------------

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    const int MAXN = 109;
    const int MAXM = 1009;
    const int MOD = 31011;
     
    struct edge {
    int u, v, w;
    bool operator < (const edge &e) const {
    return w < e.w;
    }
    } E[MAXM];
     
    int N, M, L, R, p_c, fa_c, tot, ans = 1;
    int h[MAXN], cnt[MAXN], n;
    int p[MAXN], fa[MAXN], par[MAXN];
    bool chosen[MAXM];
     
    int Find(int par[], int x) {
    return x == par[x] ? x : par[x] = Find(par, par[x]);
    }
     
    inline void InitDsu(int par[]) {
    for(int i = 0; i < N; i++) par[i] = i;
    }
     
    void Init() {
    scanf("%d%d", &N, &M);
    for(int i = 0; i < M; i++) {
    scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
    E[i].u--; E[i].v--;
    }
    sort(E, E + M);
    h[0] = E[0].w;
    n = 1;
    for(int i = 1; i < M; i++)
    if(E[i].w != E[i - 1].w) h[n++] = E[i].w;
    h[n] = -1;
    }
     
    void Dfs(int x, int c) {
    if(!c) {
    memcpy(fa, par, sizeof fa);
    int Delta = 0;
    for(int i = L; i < x; i++) if(chosen[i]) {
    int u = Find(fa, E[i].u), v = Find(fa, E[i].v);
    if(u != v)
    Delta++, fa[u] = v;
    }
    if(Delta + p_c == fa_c) tot++;
    return;
    }
    if(x >= R) return;
    chosen[x] = true; Dfs(x + 1, c - 1);
    chosen[x] = false; Dfs(x + 1, c);
    }
     
    int main() {
    Init();
    InitDsu(p);
    for(int i = 0; i < M; i++) {
    int u = Find(p, E[i].u), v = Find(p, E[i].v);
    if(u != v)
    p[u] = v;
    }
    for(int i = 1; i < N; i++) if(Find(p, i) != Find(p, i - 1)) {
    puts("0"); return 0;
    }
    memset(chosen, 0, sizeof chosen);
    InitDsu(p);
    p_c = N; R = 0;
    for(int i = 0; i < n; i++) {
    for(L = R; E[L].w == E[R].w; R++);
    int cnt = 0;
    fa_c = p_c;
    memcpy(par, p, sizeof p);
    for(int j = L; j < R; j++) {
    int u = Find(p, E[j].u), v = Find(p, E[j].v);
    if(u != v)
    p[u] = v, p_c--, cnt++;
    }
    tot = 0;
    Dfs(L, cnt);
    (ans *= tot) %= MOD;
    }
    printf("%d ", ans);
    return 0;
    }

    ------------------------------------------------------------------------------------- 

    1016: [JSOI2008]最小生成树计数

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 3916  Solved: 1557
    [Submit][Status][Discuss]

    Description

    现在给出了一个简单无向加权图。你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。由于不同的最小生成树可能很多,所以你只需要输出方案数对31011的模就可以了。

    Input

    第一行包含两个数,n和m,其中1<=n<=100; 1<=m<=1000; 表示该无向图的节点数和边数。每个节点用1~n的整数编号。接下来的m行,每行包含两个整数:a, b, c,表示节点a, b之间的边的权值为c,其中1<=c<=1,000,000,000。数据保证不会出现自回边和重边。注意:具有相同权值的边不会超过10条。

    Output

    输出不同的最小生成树有多少个。你只需要输出数量对31011的模就可以了。

    Sample Input

    4 6
    1 2 1
    1 3 1
    1 4 1
    2 3 2
    2 4 1
    3 4 1

    Sample Output

    8

    HINT

    Source

  • 相关阅读:
    jedisPool.returnBrokenResource 弃用
    错误,各种错误
    Spring加载resource时classpath*:与classpath:的区别
    Embedded database support
    IDEA 中 显示 *.properties 为中文
    Key promoter IDEA 快捷键 提示 插件
    Win7系统怎么删除今日热点【系统天地】
    win10深度清理c盘垃圾的方法【系统天地】
    win7系统如何清理注册表残留
    win10系统文件无法复制到u盘怎么办【系统天地】
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5027327.html
Copyright © 2011-2022 走看看