zoukankan      html  css  js  c++  java
  • BNUOJ 52303 Floyd-Warshall Lca+bfs最短路

    题目链接:

    https://www.bnuoj.com/v3/problem_show.php?pid=52303

    Floyd-Warshall

    Time Limit: 60000ms
    Memory Limit: 1048576KB
    #### 问题描述 > In ICPCCamp, there are n cities and m (bidirectional) roads between cities. The i-th road is between the > ai-th city and the bi-th city. There may be roads connecting a citie to itself and multiple roads between > the same pair of cities. > Bobo has q travel plans. The i-th plan is to travel from the ui-th city to the vi-th city. He would like > to know the smallest number of roads needed to travel for each plan. It is guaranteed that cities are > connected.

    输入

    The first line contains 3 integers n, m, q (1 ≤ n ≤ 105
    , 0 < m − n < 100, 1 ≤ q ≤ 105
    ).
    The i-th of the following m lines contains 2 integers ai
    , bi (1 ≤ ai
    , bi ≤ n).
    The i-th of the last q lines contains 2 integers ui
    , vi (1 ≤ ui
    , vi ≤ n).

    输出

    n lines with integers l1, l2, . . . , ln. li denotes the smallest number of roads travelling from city ui to city
    vi
    .

    样例输入

    4 5 3
    1 2
    1 3
    1 4
    2 3
    3 4
    2 2
    2 3
    2 4

    样例输出

    0
    1
    2

    题意

    给你n个点,m条无相边,q个询问,查询u到v的最短路。

    题解

    首先n有105,所以n2的bfs暴力每个源点是不可能的。
    那么这题有什么特点呢?m-n<100,明显是张稀疏图!
    如果题目给的是一颗树,那么我们就可以用logn的算法处理一个询问。(倍增LCA
    因此我们可以考虑把图拆出一颗树(其实是森林),吧所有非树边的点都存起来,对它们跑bfs求到所有其他点的最短路。
    对于一个查询,首先我们先用logn求只经过树边的最短路,然后暴力枚举会进过的一个非树边上的顶点x,用d(u,x)+d(x,v)来更新答案。 这样就处理完了。

    代码

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<functional>
    #include<sstream>
    using namespace std;
    #define X first
    #define Y second
    #define mkp make_pair
    #define lson (o<<1)
    #define rson ((o<<1)|1)
    #define mid (l+(r-l)/2)
    #define sz() size()
    #define pb(v) push_back(v)
    #define all(o) (o).begin(),(o).end()
    #define clr(a,v) memset(a,v,sizeof(a))
    #define bug(a) cout<<#a<<" = "<<a<<endl
    #define rep(i,a,b) for(int i=a;i<(b);i++)
    #define scf scanf
    #define prf printf
    
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<pair<int,int> > VPII;
    
    const int INF=0x3f3f3f3f;
    const LL INFL=0x3f3f3f3f3f3f3f3fLL;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    
    //start----------------------------------------------------------------------
    
    //数据需要开大点,否则会出现tle、re的情况。。。
    const int maxn=101010;
    const int maxm=18;
    
    struct Edge {
        int u,v,ne,flag;
        Edge(int u,int v,int ne):u(u),v(v),ne(ne) {
            flag=0;
        }
        Edge() {}
    } egs[maxn*2];
    
    int head[maxn],tot;
    int used[maxn];
    
    void addEdge(int u,int v) {
        egs[tot]=Edge(u,v,head[u]);
        head[u]=tot++;
    }
    
    //dep:深度,fa:父亲,anc:祖先
    int dep[maxn],fa[maxn],vis[maxn];
    int anc[maxn][maxm];
    void dfs(int u,int f,int d) {
        vis[u]=1;
        dep[u]=d;
        fa[u]=f;
    
        anc[u][0]=f;
        for(int i=1; i<maxm; i++) {
            anc[u][i]=anc[anc[u][i-1]][i-1];
        }
    
        for(int p=head[u]; p!=-1; p=egs[p].ne) {
            Edge& e=egs[p];
            if(e.v==f) continue;
            if(!vis[e.v]) {
                dfs(e.v,u,d+1);
            } else {
                used[u]=used[e.v]=1;
            }
        }
    }
    
    //dis:非树边上的点到所有点的距离
    int dis[222][maxn];
    //ha:存非树边上的点
    int ha[222],last;
    int myque[maxn],frt,rear;
    void bfs(int id) {
        int s=ha[id];
        frt=0,rear=0;
        dis[id][s]=0;
        myque[rear++]=s;
        clr(vis,0);
        vis[s]=1;
        while(frt<rear) {
            int u=myque[frt++];
            for(int p=head[u]; p!=-1; p=egs[p].ne) {
                Edge& e=egs[p];
                if(vis[e.v]) continue;
                vis[e.v]=1;
                dis[id][e.v]=dis[id][u]+1;
                myque[rear++]=e.v;
            }
        }
    }
    
    int Lca(int u,int v) {
        if(dep[u]<dep[v]) swap(u,v);
        for(int i=maxm-1; i>=0; i--) {
            if(dep[anc[u][i]]>=dep[v]) {
                u=anc[u][i];
            }
        }
        if(u==v) return u;
        for(int i=maxm-1; i>=0; i--) {
            if(anc[u][i]!=anc[v][i]) {
                u=anc[u][i];
                v=anc[v][i];
            }
        }
        return anc[u][0];
    }
    
    int n,m,q;
    
    int main() {
        scf("%d%d%d",&n,&m,&q);
        clr(used,0);
        clr(head,-1);
        tot=0;
        //建图
        for(int i=0; i<m; i++) {
            int u,v;
            scf("%d%d",&u,&v);
            if(u==v) continue;
            addEdge(u,v);
            addEdge(v,u);
        }
    
        //处理出树边、非树边
        clr(vis,0);
        clr(anc,0);
        for(int i=1; i<=n; i++) {
            if(!vis[i]) {
                dfs(i,0,1);
            }
        }
    
        //把非树边上的点存起来
        last=0;
        for(int i=1; i<=n; i++) if(used[i]) {
            ha[last++]=i;
        }
    
        //跑非树边上的点到所有点的距离
        clr(dis,0x3f);
        rep(i,0,last) bfs(i);
    
        while(q--) {
            int u,v;
            scf("%d%d",&u,&v);
            int lca=Lca(u,v);
            LL res=dep[u]+dep[v]-2*dep[lca];
            rep(i,0,last) {
                LL tmp=(LL)dis[i][u]+dis[i][v];
                res=min(res,tmp);
            }
            prf("%lld
    ",res);
        }
    
        return 0;
    }
    
    //end-----------------------------------------------------------------------
  • 相关阅读:
    接口中解决默认方法冲突
    继承中的访问域问题
    继承中的多态问题
    Java中方法的调用过程
    【JS】表格获取每一列方法
    【Git报错】 ! [rejected] master -> master (fetch first)
    【Vue】vue-cli配置proxyTable调用服务器接口
    layui监听多个radio事件
    【总结】display属性inline,block,inline-block
    【实例总结】fixed定位元素内部滚动显示
  • 原文地址:https://www.cnblogs.com/fenice/p/5928440.html
Copyright © 2011-2022 走看看