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;

posted on 2020-09-23 08:11  fishsit  阅读(94)  评论(0编辑  收藏  举报

导航