• NOIP 2013 P1967 货车运输


    倍增求LCA+最大生成树

    题目给出的是一张图,在图上有很多算法无法实现,所以要将其转化为树

    题中可以发现货车的最后的载重量是由权值最小的一条边决定的,所以我们求最大生成树

    求完最大生成树后我们得到一个森林

    现在转化为了求两点路径经过边的边权的最小值,用倍增算法进行计算

    #include <bits/stdc++.h>
    #define inf 1e9
    using namespace std;
    const int MAXN=10100;
    int n,m,first[MAXN],nxt[MAXN*10],point[MAXN*10],len[MAXN*10];
    int q,tot,fa[MAXN],f[MAXN][21],chmin[MAXN][21],vi[MAXN],de[MAXN];
    struct node
    {
        int u,v,len;
    }sh[MAXN*5];
    void add_edge(int x,int y,int z)
    {
        tot++;
        nxt[tot]=first[x];
        first[x]=tot;
        point[tot]=y;
        len[tot]=z;
    }
    void dfs(int x,int father,int deep,int last,int visit)
    {
        de[x]=deep;
        vi[x]=visit;
        f[x][0]=father;//倍增father数组
        chmin[x][0]=last;//记录上一条边的权值
        for (int i=first[x];i!=-1;i=nxt[i])
        {
            if (point[i]!=father)
            {
                dfs(point[i],x,deep+1,len[i],visit);
            }
        }
    }
    int getfather(int x)
    {
        if (fa[x]==x)
          return fa[x];
        fa[x]=getfather(fa[x]);
        return fa[x];
    }
    bool cmp(node a,node b)
    {
        return a.len>b.len;
    }
    int lca(int a,int b)//倍增求LCA
    {
        if (getfather(a)!=getfather(b))
          return -1;
        if (de[a]>de[b])
          swap(a,b);
        int MIN=inf;
        for (int i=20;i>=0;i--)
        {
            if (de[f[b][i]]>=de[a])
            {
                MIN=min(MIN,chmin[b][i]);
                b=f[b][i];
            }
        }
        if (a==b)
          return MIN;
        for (int i=20;i>=0;i--)
        {
            if (f[a][i]!=f[b][i])
            {
                MIN=min(MIN,min(chmin[a][i],chmin[b][i]));
                a=f[a][i];
                b=f[b][i];
            }
        }
        MIN=min(MIN,min(chmin[a][0],chmin[b][0]));
        return MIN;
    }
    int main()
    {
        tot=-1;
        memset(nxt,-1,sizeof(nxt));
        memset(first,-1,sizeof(first));
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&sh[i].u,&sh[i].v,&sh[i].len);
        }
        for (int i=1;i<=n;i++)
          fa[i]=i;
        sort(sh+1,sh+1+m,cmp);
        for (int i=1;i<=m;i++)
        {
            if (getfather(sh[i].u)!=getfather(sh[i].v))
            {
                fa[getfather(sh[i].u)]=getfather(sh[i].v);
                add_edge(sh[i].u,sh[i].v,sh[i].len);
                add_edge(sh[i].v,sh[i].u,sh[i].len);
            }
        }//求最大生成树
        int now=0;
        for (int i=1;i<=n;i++)//可能有多棵树,每棵树分别考虑
        {
            if (vi[i]!=0)
              continue;
            now++;
            dfs(i,0,0,inf,now);
            f[i][0]=i;
            chmin[i][0]=inf;
        }
        for (int j=1;j<=20;j++)
        {
            for (int i=1;i<=n;i++)
            {
                f[i][j]=f[f[i][j-1]][j-1];
                chmin[i][j]=min(chmin[i][j-1],chmin[f[i][j-1]][j-1]);//进行倍增
            }
        }
        scanf("%d",&q);
        for (int i=1;i<=q;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d
    ",lca(x,y));
        }
    }

    倍增求LCA时避免父亲倍增数组出现0,倍增记录最小值时,简单写法

        int now=0;
        for (int i=1;i<=n;i++)
        {
            if (vi[i]!=0)
              continue;
            now++;
            dfs(i,0,0,inf,now);
            f[i][0]=i;//使当前的father==i
            chmin[i][0]=inf;//记录的最小值
        }

    求deep时,注意不是求距离上的deep,而是层数

    void dfs(int x,int father,int deep,int last,int visit)
    {
        de[x]=deep;
        vi[x]=visit;
        f[x][0]=father;
        chmin[x][0]=last;
        for (int i=first[x];i!=-1;i=nxt[i])
        {
            if (point[i]!=father)
            {
                dfs(point[i],x,deep+1,len[i],visit);//deep是+1,不是加len[i],注意
            }
        }
    }
  • 相关阅读:
    【汇编程序】出地址为BUF的5个字符数组的内容之和
    Ugly Number
    Best Time to Buy and Sell Stock IV****
    Best Time to Buy and Sell Stock III
    Best Time to Buy and Sell Stock
    Best Time to Buy and Sell Stock II
    House Robber II
    Contain Duplicate III*******
    Contain Duplicate II
    Contain Duplicate
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/11128841.html
Copyright © 2020-2023  润新知