zoukankan      html  css  js  c++  java
  • bzoj 1016 深搜

      首先我们知道MST的一些性质,对于这道题来说就是,假设我们先求出一颗MST设为G,由已知边权相同的边最多会有10条,那么假设我们在这10条边中选取size条边∈G,那么我们在这边权相同的边集E中任意选取size条有意义的边,这里的有意义的边的定义为每条边都会造成新的连通性的增加,那么边集E中所有的size条有意义的边的方案我们可以通过dfs求出,然后我们将不同边权的边的方案求连乘,就是MST的方案数。

      ps:我们没有必要求一遍MST,我们可以一边做kruskal,一边维护图的连通性,然后每找到一个权值不同的边集E时深搜。

      反思:做dfs的时候使用并查集维护图的连通性,但是加了路径压缩,这样就会在找块的祖先的时候改变不同节点的父亲,这样就没有办法在dfs时恢复原图,所以我们应该只用并查集维护节点的父亲而不是祖先,找了半天才找到这里的错误。

      

    /**************************************************************
        Problem: 1016
        User: BLADEVIL
        Language: C++
        Result: Accepted
        Time:8 ms
        Memory:820 kb
    ****************************************************************/
     
    //By BLADEVIL
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 110
    #define maxm 1010
    #define d39 31011
     
    using namespace std;
     
    int n,m;
    int father[maxn],curfather[maxn];
    struct rec
    {
        int a,b,len;
    } c[maxm];
     
    bool cmp(rec a,rec b)
    {return (a.len<b.len);}
     
    int getfather(int x)
    {
        if (father[x]==x) return x;
        return father[x]=getfather(father[x]);
    }
     
    int getcurfather(int x)
    {
        if (curfather[x]==x) return x;
        return getcurfather(curfather[x]);
    }
     
    int dfs(int l,int r,int size)
    {
        //printf("%d %d %d
    ",l,r,size);
        if (!size) return 1;
        if (l>r) return 0;
        int fa,fb,cur=0;
        cur=dfs(l+1,r,size);
        fa=getcurfather(c[l].a); fb=getcurfather(c[l].b);
        if (fa!=fb)
        {
            curfather[fa]=fb;
            cur+=dfs(l+1,r,size-1);
            curfather[fa]=fa;
        }
        return cur;
    }
     
    int main()
    {
        int ans=1,cnt=0;
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++) scanf("%d%d%d",&c[i].a,&c[i].b,&c[i].len);
        sort(c+1,c+m+1,cmp);
        for (int i=1;i<=n;i++) father[i]=curfather[i]=i;
        int cur=0;
        int l,r,size=0;
        for (int i=1;i<=m+1;i++)
        {
            if (cur!=c[i].len)
            {
                r=i-1;
                //if (i!=1) printf(" %d %d %d
    ",l,r,size);
                if (i!=1) ans=(ans*=dfs(l,r,size))%d39;
                l=i;
                size=0;
                cur=c[i].len;
                memcpy(curfather,father,sizeof curfather);
            }
            int fa,fb;
            fa=getfather(c[i].a); fb=getfather(c[i].b);
            if (fa!=fb)
            {
                size++;
                cnt++;
                father[fa]=fb;
            }
        }
        if (cnt!=n-1) printf("0
    "); else printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    常见hash算法的原理
    【学习干货】给coder的10个读书建议
    htc one x刷机记录
    Linux 搭建SVN server
    javascript
    USACO comehome Dijkstra
    当设计师、产品经理和程序员去交友站点找女朋友
    Spring3.0 AOP 具体解释
    慕课网Hibernate初探之一对多映射实验及总结
    C++数组引用
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3551852.html
Copyright © 2011-2022 走看看