zoukankan      html  css  js  c++  java
  • [NOIP 2013] 货车运输 题解

    题解:

    首先,题目要求我们求两点间所有路径的最小边权,我们要做的是最大化这个最小边权,我们可以搞一颗图的最大生成树,这样这个最小边权一定是最大的。我们可以考虑反证法,若存在另一条路径上的最小边权大于最大生成树上的路径的最小边权,那么显然我们可以通过断掉最大生成树上的边连另外一条边更大化这个最大生成树(建议画图理解),与最大生成树的定义矛盾。

    我们可以用$Kruskal$算法求出这个最大生成树,考虑如何快速求出两个点的路径,因为两点之间的路径可以分解成为它们的$lca$到这两个点的路径,我们可以选择在求询问的两点的$lca$时结合倍增顺便将最短路径求出,具体来说就是用两个数组$f[i,j],dp[i,j]$分别表示节点$i$到它的$2^j$次方祖先节点的节点编号与路径上的最小权值。
    那么有:

    $dp[i,j]=min(dp[i,j-1],dp[f[i,j-1],j-1])$

    这两个皆可以一遍$dfs$求出。

    需要注意的细节:这个图可能是不连通的,求$dfs$时注意将所有的最大生成树都dfs一遍。

    最后附上代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=10005,M=50005,inf=(1<<30);
    
    int c[N],ver[M],nxt[M],edge[M],head[N],d[N],f[N][20],dp[N][20];
    int n,m,cnt,tot,t,q;
    bool vis[N];
    
    struct point{
        int u,v,len;
        bool operator < (const point &a)const{return a.len<len;}
    }edge1[M];
    
    int read(){
        int x=0;
        char ch=getchar();
        while(ch<'0' || ch>'9') ch=getchar();
        while(ch>='0' && ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x;
    }
    
    int getfather(int x){return x==c[x] ? x : c[x]=getfather(c[x]);}
    void add(int x,int y,int z){ver[++tot]=y,edge[tot]=z,nxt[tot]=head[x],head[x]=tot;}
    
    void dfs(int x){
        vis[x]=1;
        for(int i=head[x],y;i;i=nxt[i]){
            if(vis[y=ver[i]]) continue;
            d[y]=d[x]+1,f[y][0]=x,dp[y][0]=edge[i];
            for(int j=1;j<=t;++j){
                f[y][j]=f[f[y][j-1]][j-1];
                dp[y][j]=min(dp[y][j-1],dp[f[y][j-1]][j-1]);
            }
            dfs(y);
        }
    }
    
    int LCA(int x,int y){
        int ans=inf;
        if(d[x]>d[y]) swap(x,y);
        for(int i=t;i>=0;--i){
            if(d[f[y][i]]>=d[x]){
                ans=min(ans,dp[y][i]);
                y=f[y][i];
            }
        }
        if(x==y) return ans;
        for(int i=t;i>=0;i--){
            if(f[x][i]!=f[y][i]){
                ans=min(ans,min(dp[x][i],dp[y][i]));
                x=f[x][i],y=f[y][i];
            }
        }
        return ans=min(ans,min(dp[x][0],dp[y][0]));
    }
    
    int main(){
        n=read(),m=read();
        t=(int)(log(n)/log(2))+2;
        for(int i=1;i<=m;++i) edge1[++cnt].u=read(),edge1[cnt].v=read(),edge1[cnt].len=read();
        for(int i=1;i<=n;++i) c[i]=i;
        sort(edge1+1,edge1+1+cnt);
        for(int i=1;i<=cnt;++i){//Kruskal求最大生成树
            int x=edge1[i].u,y=edge1[i].v,z=edge1[i].len;
            int faa=getfather(x),fab=getfather(y);
            if(faa==fab) continue;
            c[fab]=faa;
            add(x,y,z),add(y,x,z);
        }
        for(int i=1;i<=n;++i) if(!vis[i]){d[i]=1,dfs(i);}
        q=read();
        for(int i=1,x,y;i<=q;++i){
            x=read(),y=read();
            int faa=getfather(x),fab=getfather(y);
            if(faa!=fab){printf("-1
    ");continue;}//不在一个连通块内
            printf("%d
    ",LCA(x,y));
        }
        return 0;
    }
  • 相关阅读:
    es6-compact-table 名词备忘
    JS 防抖和节流函数
    为什么 JS 对象内部属性遍历的顺序乱了
    JS 发送 HTTP 请求方法封装
    JS 一些位操作的妙用
    JS 格式化时间
    linux ssh连接
    c# checked 和 unchecked
    c# mvc action 跳转方式
    IIS 动态与静态压缩
  • 原文地址:https://www.cnblogs.com/Asika3912333/p/11823473.html
Copyright © 2011-2022 走看看