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;
    
  • 相关阅读:
    20145334赵文豪《网络对抗》 后门原理与实践
    20145334赵文豪《网络对抗》-逆向及Bof基础实践
    20145333茹翔《网络对抗》Exp9 Web安全基础实践
    20145333茹翔 Exp8 Web基础
    20145333茹翔 Exp7 网络欺诈技术防范
    20145333茹翔《网络对抗技术》Exp6 信息搜集技术
    20145333茹翔 Exp5 MSF基础应用
    20145333茹翔 Exp5 利用nmap扫描
    20145333茹翔 Exp5 Adobe阅读器漏洞攻击
    20145333茹翔 Exp5 MS11_050
  • 原文地址:https://www.cnblogs.com/scy-fisheep/p/13716108.html
Copyright © 2011-2022 走看看