zoukankan      html  css  js  c++  java
  • 【题解】洛谷P1967 [NOIP2013TG] 货车运输(LCA+kruscal重构树)

    洛谷P1967:https://www.luogu.org/problemnew/show/P1967

    思路

    感觉2013年D1T3并不是非常难

    但是蒟蒻还是WA了一次

    从题目描述中看出每个点之间有许多条路径

    而我们需要的是找出整条路径中最大的最小可通过量

    一开始看到题目会想到是不是最大流问题 但是仔细一想其实并不用那么麻烦

    我们只需要用kruscal找出最大生成树即可(因为多条路径中只要挑出最大的即可)

    然后在重构树上考虑怎么取到两点之间的最小值

    我们发现图是一个或者是多个树(没有考虑WA了一次)

    所以我们可以用LCA代替朴素算法查找最小值 用一个m1[x][k]数组维护x到x的2k辈祖先路径中的最小值

    这样题目就可以轻松A过

    代码

    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 10010
    #define INF 100010
    int n,m,q,k,cnt;
    int fa[maxn],f[maxn][32],m1[maxn][32],h[maxn],dep[maxn];
    //fa为kruscal的父亲数组 f为LCA的父亲数组 
    bool vis[maxn];
    struct Node
    {
        int l;
        int r;
        int w;
    }node[maxn*5];//原图的边
    struct Edge
    {
        int nex;
        int to;
        int w;
    }e[maxn*5];//重构树的边 
    void add(int u,int v,int w)
    {
        e[++cnt].to=v;
        e[cnt].w=w;
        e[cnt].nex=h[u];
        h[u]=cnt;
    }
    bool cmp(Node a,Node b)//从大到小 
    {
        return a.w>b.w;
    }
    int find(int x)
    {
        if(fa[x]!=x)
        fa[x]=find(fa[x]);
        return fa[x];
    }
    void pre()
    {
        for(int i=1;i<=17;i++)
        {    
            for(int j=1;j<=n;j++)
            {
                f[j][i]=f[f[j][i-1]][i-1];
                m1[j][i]=min(m1[j][i-1],m1[f[j][i-1]][i-1]);//从儿子来取 
            }
        }
    }
    int lca(int x,int y)
    {
        if(find(x)!=find(y)) return -1;//如果不在同一棵树中就不能到达 
        int ans=INF;//初始化 
        if(dep[x]<dep[y]) swap(x,y);
        for(int k=17;k>=0;k--)
        {
            if(dep[f[x][k]]>=dep[y])  
            {
                ans=min(ans,m1[x][k]);//取最小值 
                x=f[x][k];
            }
            if(x==y) return ans;
        }
        for(int k=17;k>=0;k--)
        {
            if(f[x][k]!=f[y][k])
            {
                ans=min(ans,min(m1[x][k],m1[y][k]));//取最小值 
                x=f[x][k];
                y=f[y][k];
            }
        }
        ans=min(ans,min(m1[x][0],m1[y][0]));//取父亲的最小值 
        return ans;
    }
    void dfs(int u)
    {
        vis[u]=1;//判断已经在树中 
        for(int i=h[u];i;i=e[i].nex)
        {
            int v=e[i].to;
            if(vis[v]) continue;//如果在树中就跳过 
            dep[v]=dep[u]+1;//记录深度 
            f[v][0]=u;//记录父亲 
            m1[v][0]=e[i].w;//初始化最小值为边权值 
            dfs(v);
        }
        return;
    }
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=m;i++) cin>>node[i].l>>node[i].r>>node[i].w;
        sort(node+1,node+1+m,cmp);
        for(int i=1;i<=m;i++)//kruscal
        {
            if(find(node[i].l)!=find(node[i].r))
            {
                fa[find(node[i].l)]=find(node[i].r);
                add(node[i].l,node[i].r,node[i].w);//重构图 
                add(node[i].r,node[i].l,node[i].w);
                k++;
            }
            if(k==n-1) break;
        }
        for(int i=1;i<=n;i++)//预处理LCA 
            if(!vis[i])//判断是不是同一棵树 
            {
                dep[i]=1;//树根的深度为1 
                dfs(i);
                f[i][0]=i;//树根的父亲为自己 
                m1[i][0]=INF;//树根到父亲的最小值为一个极大值 
            }
        pre();//预处理m1数组和f数组 
        cin>>q;
        for(int i=1;i<=q;i++)
        {
            int x,y;
            cin>>x>>y;
            cout<<lca(x,y)<<endl;
        }
    }
  • 相关阅读:
    C# 实现 Snowflake算法生成唯一性Id
    kafka可视化客户端工具(Kafka Tool)的基本使用(转)
    docker 安装kafka
    Model类代码生成器
    使用docker 部署rabbitmq 镜像
    Vue 增删改查 demo
    git 提交代码到库
    Android ble蓝牙问题
    mac 配置 ssh 到git (Could not resolve hostname github.com, Failed to connect to github.com port 443 Operation timed out)
    okhttp
  • 原文地址:https://www.cnblogs.com/BrokenString/p/9833246.html
Copyright © 2011-2022 走看看