• [題解](最小生成樹/LCA)luogu_P1967貨車運輸


    一道好題不出所料又抄的題解


    1.首先對於這張圖肯定要考慮走哪些邊不走哪些邊,發現我們想要的肯定那些邊權最大的邊,所以想到最大生成樹

    這樣能保證選到盡量大的邊

    2.跑完最大生成樹后每兩點之間就有唯一路徑了,想要知道兩點間最小邊權,可以在LCA過程中求出(我竟然不會LCA),對lca做些許改動

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=10010;
    const int maxm=50010;
    struct node1{
        int u,v,w;
    }e1[maxm];
    struct node2{
        int v,w,nxt;
    }e2[maxm*2];
    int head[maxn],cnt;
    int n,m;
    int dep[maxn],f[maxn],fa[maxn][21],w[maxn][21];
    //f数组表示并查集中的父节点,fa数组表示树上的父节点,w数组表示最大载重 
    bool v[maxn];
    void add(int u,int v,int w){
        e2[++cnt].v=v;e2[cnt].w=w;e2[cnt].nxt=head[u];head[u]=cnt;
    }
    bool cmp(node1 x,node1 y){
        return x.w>y.w;
    }
    int find(int x){
        while(x!=f[x])x=f[x]=f[f[x]];return x;
    }
    void kruskal(){
        sort(e1+1,e1+1+m,cmp);
        for(int i=1;i<=n;i++)f[i]=i;
        for(int i=1;i<=m;i++){
            int x=find(e1[i].u),y=find(e1[i].v);
            if(x==y)continue;
            f[x]=y;
            add(e1[i].u,e1[i].v,e1[i].w);
            add(e1[i].v,e1[i].u,e1[i].w);
        }
    }
    void dfs(int x){
        v[x]=1;
        for(int i=head[x];i;i=e2[i].nxt){
            int y=e2[i].v;
            if(v[y])continue;
            dep[y]=dep[x]+1;
            fa[y][0]=x;//儲存父節點 
            w[y][0]=e2[i].w;
            dfs(y);
        }
    }
    int lca(int x,int y){//lca過程中求邊權最小值 
        if(find(x)!=find(y))return -1;//不連通 
        int ans=0x7fffffff;
        if(dep[x]>dep[y])swap(x,y);
        //將y節點提升到x相同高度 
        for(int i=20;i>=0;i--)
        if(dep[fa[y][i]]>=dep[x])
        ans=min(ans,w[y][i]),y=fa[y][i];
        if(x==y)return ans;
        
        for(int i=20;i>=0;i--)
        if(fa[x][i]!=fa[y][i]){
            ans=min(ans,min(w[x][i],w[y][i]));
            x=fa[x][i];y=fa[y][i];
        }
        ans=min(ans,min(w[x][0],w[y][0]));
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)scanf("%d%d%d",&e1[i].u,&e1[i].v,&e1[i].w);
        kruskal();
        for(int i=1;i<=n;i++)
        if(!v[i]){
            dep[i]=1;
            dfs(i);
            fa[i][0]=i;
            w[i][0]=0x7fffffff;
        }
        //lca初始化 
        for(int i=1;i<=20;i++)
        for(int j=1;j<=n;j++){
            fa[j][i]=fa[fa[j][i-1]][i-1];
            w[j][i]=min(w[j][i-1],w[fa[j][i-1]][i-1]);
        }
        int q;
        scanf("%d",&q);
        while(q--){
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d
    ",lca(x,y));
        }
    }
  • 相关阅读:
    BlockingQueue
    序列化存取数据库(spring+mybatis+oracle) 以及可能会遇到的数据库取出的数据反序列化失败问题
    关于junit不抛出异常
    关于ByteArrayInputStream、ByteArrayOutputStream 和 ObjectInputStream、ObjectOutputStream
    sc delete mysql命令执行失败
    python中的值传递和引用传递
    flask实现模仿知乎
    协程和装饰器完成简易计算器
    微信JSAPI支付接口,支付完成后关闭当前窗口
    Java关键字transient和volatile小结
  • 原文地址:https://www.cnblogs.com/superminivan/p/10738603.html
Copyright © 2020-2023  润新知