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-----------------------------------------------------------------------
  • 相关阅读:
    bzoj 4012: [HNOI2015]开店
    POJ 1054 The Troublesome Frog
    POJ 3171 Cleaning Shifts
    POJ 3411 Paid Roads
    POJ 3045 Cow Acrobats
    POJ 1742 Coins
    POJ 3181 Dollar Dayz
    POJ 3040 Allowance
    POJ 3666 Making the Grade
    洛谷 P3657 [USACO17FEB]Why Did the Cow Cross the Road II P
  • 原文地址:https://www.cnblogs.com/fenice/p/5928440.html
Copyright © 2011-2022 走看看