zoukankan      html  css  js  c++  java
  • 20200923 货车运输

    题面
    因为有一点忘了算法,然后想借助题来复习一下,所以有一些算法会复习的比较详细。
    首先可以看到,这是一个先以(1)为根建一颗最大生成树,再用倍增求(LCA)

    并查集

    具体来说现将一个集合的中所有元素进行个体分离,然后根据关系进行集合,最后判断几个点是否有关系只需判断是否在一个集合中即可。

    int find(int t)
    {
        if(f[t]==t)
        {
            return t;
        }
        else
        {
            return f[t]=find(f[t]);
        }
    }
    

    最大生成树


    我们将对边权进行排序,边权大的将被优先选择。选边时,若这一条边的两个顶点不在一个集合内就将二者合并,这里就用到了并查集的思想,并将加入的边的条数增加(1),然后建边,当已经选了(n-1)条边时就跳出循环,因为(n)个点需要(n-1)条边才能够两两互达且为树。
    下面就是该图的最大生成树:

    倍增

    1号点第(i)次跳跃跳到的格子为(1+2^i)。那么如果我们设(g[x][i])表示的是(x)号点跳第(i)次的位置的话,那么(g[x][i]=g[g[x][i−1]][i−1]),此处感觉十分的好理解。显然,我们可以先从(x)点跳到离(y)点最近的且不超过(y)点的那个点。然后再从该点起步,继续跳下去,直到跳到(y)点为止。这种算法的时间复杂度为(O(nlog2n))

    LCA

    最近一直在刷LCA的题,然后就不在这里展开讲了。

    int lca(int x,int y)
    {
        int ans=inf;
        if(deep[x]<deep[y])
        {
            int t=x;
            x=y;
            y=t;
        }
        for(int i=20;i>=0;i--)
        {
            if(deep[p[x][i]]>=deep[y])
            {
                ans=min(ans,w[x][i]);
                x=p[x][i];
            }
        }
        if(x==y)
        {
            return ans;
        }
        for(int i=20;i>=0;i--)
        {
            if(p[x][i]!=p[y][i])
            {
                ans=min(ans,min(w[x][i],w[y][i]));
                x=p[x][i];
                y=p[y][i];
                
            }
        }
        ans=min(ans,min(w[x][0],w[y][0]));
        return ans;
    }
    

    注意了,当有(2)棵树或多棵树时,要将没有深度的点(即不与点(1)在同一棵树内的点)的深度改为(1),如果不改的话就会输出(0)哦。

    下面我将把代码中的一些重要的部分拆开来解释,方便大家理解。

    代码段还请见(lca())部分。

    因为我们规定了是(x)去找(y),所以当(y)(x)深时就要交换(x)(y)。调换(x)(y)并不会影响答案,因为(lca(x,y)=lca(y,x))

    if(deep[x]<deep[y])
    {
        int t=x;
        x=y;
        y=t;
    }
    

    这里是让(x)和跳到和(y)同一层,并在路上记录最小值, 若(y)就是(x)的公共祖先(见下图)就直接返回答案即可。否则就让(x)(y)一起跳到它们的最近公共祖先的前一步的那个点去,最后再跳一步(即跳到(x)(y)的最近公共祖先那里去)。最后再返回所经过的路径中的最小值即可。注意赋值的顺序不要反了。

    for(int i=20;i>=0;i--)
    {
        if(deep[p[x][i]]>=deep[y])
        {
            ans=min(ans,w[x][i]);
            x=p[x][i];
        }
    }
        if(x==y)
        {
            return ans;
        }
        for(int i=20;i>=0;i--)
        {
            if(p[x][i]!=p[y][i])
            {
                ans=min(ans,min(w[x][i],w[y][i]));
                x=p[x][i];
                y=p[y][i];
            }
        }
        ans=min(ans,min(w[x][0],w[y][0]));
        return ans;
    
  • 相关阅读:
    三数之和
    罗马数字与整数
    Oracle 开启或关闭归档
    Oracle RMAN scripts to delete archivelog
    Oracle check TBS usage
    Oracle kill locked sessions
    场景9 深入RAC运行原理
    场景7 Data Guard
    场景4 Data Warehouse Management 数据仓库
    场景5 Performance Management
  • 原文地址:https://www.cnblogs.com/scy-fisheep/p/13716108.html
Copyright © 2011-2022 走看看