• luogu [USACO08OCT]打井Watering Hole


    原题链接:

    一道巧妙的最小生成树。

    与最小生成树不同的是,本题因为有打井的存在,所以可以不只有一棵生成树,但是克鲁斯卡尔算法依然十分好用。

    首先按照题目要求读入边,虽然题目中给出的是近似邻接矩阵的写法,但是因为要使用克鲁斯卡尔算法,要将其转换成类似邻接表的写法。

    对于每一组(i<j)就可以将(i,j,c)这一条边加入。

    那么如何处理打井的情况呢?我们可以假想有一个n+1号节点,代表地下水,于是我们可以将所有的(i,n+1,w[i])加入。

    这样就有(n-1)*n/2+n条边,然后就可以做做最小生成树了,只是现在有了n+1个点,我们需要n条边了。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    void read(int &y)
    {
        y=0;char x=getchar();
        while(x<'0'||x>'9') x=getchar();
        while(x>='0'&&x<='9')
        {
            y=y*10+x-'0';
            x=getchar();
        }
    }
    struct edge
    {
        int u,v,w;
    }e[100505];
    bool cmp(edge x,edge y)
    {
        return x.w<y.w;
    }
    int n,m,tot,c,f[305],ans;
    void add(int u,int v,int w)
    {
        e[++m].u=u;
        e[m].v=v;
        e[m].w=w;
    }
    int find(int x)
    {
        if(x==f[x]) return x;
        return f[x]=find(f[x]); 
    }
    int main()
    {
        read(n);
        for(int i=1;i<=n;i++)
        {
            read(c);
            add(i,n+1,c);
            f[i]=i;
        }
        f[n+1]=n+1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                read(c);
                if(i<j) add(i,j,c);
            }
        }
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=m;i++)
        {
            if(find(e[i].u)==find(e[i].v)) continue;
            f[find(e[i].u)]=e[i].v;
            tot++;
            ans+=e[i].w;
            if(tot==n) break;
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    运行了unittest没有结果返回
    python学习笔记11.2-unittest的使用与报告生成
    python学习笔记11.1-类的继承与动态属性的设置
    docker概念
    python学习笔记10-方法
    python学习笔记9-类和对象
    python学习笔记8-异常处理
    python学习笔记2-字典和列表
    3.JavaScript-语法、关键保留字及变量
    如何实现导航菜单栏中的二级下拉菜单?
  • 原文地址:https://www.cnblogs.com/zeroform/p/7592821.html
Copyright © 2020-2023  润新知