zoukankan      html  css  js  c++  java
  • BZOJ1016:[JSOI2008]最小生成树计数——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=1016

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

    无外乎两种:K算法和P算法(当然还有第三种但是我不会(滑稽)

    P算法没法解于是用K算法。

    发现K算法的正确性后其实我们需要做的工作就是从K算法找到一些边,可以用另一些边权一样的边替换并且是一棵生成树即可。

    于是我们枚举即可。

    (当然你会有两个问题:1.为什么边权一样即可替换,2.前面的边的操作对后面边是否有影响?)

    (所以暴力选手不过脑子的话就很轻松的敲完代码走人了(比如我))

    (实际为两个定理,分别为:

    1.不同的最小生成树中,每种权值的边出现的个数是确定的。

    2.不同的生成树中,某一种权值的边连接完成后,形成的联通块状态是一样的 。

    百度一下。

    https://blog.csdn.net/jarily/article/details/8902402可能这个解释靠谱些?)

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cctype>
    #include<cstdio>
    #include<vector>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int N=101;
    const int M=1010;
    const int p=31011;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct node{
        int u,v,w;
    }e[M];
    struct range{
        int l,r;
    }a[M];
    int fa[N],t[M],n,m,k,sum;
    inline bool cmp(node a,node b){
        return a.w<b.w;
    }
    int find(int x){
        if(fa[x]==x)return x;
        return find(fa[x]);
    }
    inline void unionn(int x,int y){
        fa[x]=y;
    }
    inline void destory(int x,int y){
        fa[x]=x;fa[y]=y;
    }
    void dfs(int l,int r,int d,int w){
        if(l>r){
            if(d==t[w])sum=(sum+1)%p;
            return;
        }
        if(r-l+1+d<t[w])return;
        int u=find(e[l].u),v=find(e[l].v);
        if(u!=v&&d<t[w]){
            unionn(u,v);
            dfs(l+1,r,d+1,w);
            destory(u,v); 
        }
        dfs(l+1,r,d,w);
    }
    int main(){
        n=read(),m=read();
        for(int i=1;i<=m;i++){
            e[i].u=read(),e[i].v=read(),e[i].w=read();
        }
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=n;i++)fa[i]=i;
        int cnt=0;
        for(int i=1;i<=m;i++){
            if(e[i].w!=e[i-1].w){
                a[++k].l=i;a[k-1].r=i-1;
            }
            int u=e[i].u,v=e[i].v;
            u=find(u),v=find(v);
            if(u!=v)t[k]++,cnt++,unionn(u,v);
        }
        a[k].r=m;
        if(cnt!=n-1){
            puts("0");return 0;
        }
        int ans=1;
        for(int i=1;i<=n;i++)fa[i]=i;
        for(int i=1;i<=k;i++){
            if(!t[i])continue;
            sum=0;
            dfs(a[i].l,a[i].r,0,i);
            ans=(ll)ans*sum%p;
            for(int j=a[i].l;j<=a[i].r;j++){
                int u=e[j].u,v=e[j].v;
                u=find(u),v=find(v);
                if(u!=v)unionn(u,v);
            }
        }
        printf("%d
    ",ans);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    LeetCode344. 反转字符串
    LeetCode59. 螺旋矩阵 II
    LeetCode209. 长度最小的子数组
    LeetCode383. 赎金信
    cannot be cast to javax.servlet.Servlet
    求组合
    数据库系统概论王珊第四版 答案
    数据库复习
    dfs-bfs
    dfs
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8996369.html
Copyright © 2011-2022 走看看