NC19814 最短路(LCA+思维)

这题如果注意到m的范围,那么思路将会豁然开朗

因为如果是一棵树,那么直接lca就能求得两点间最小值

但是现在是图,并且边数就比一棵树大100左右

所以我们可以想到,先将图中取出生成树,用lca求答案

那么剩下就有100条边左右未使用,我们发现,答案可能经过这些边,因此我们枚举这些边的端点去做01最短路,对两种情况取min就是最后答案

直接做最短路的正确性在于,如果答案使用到了某条未在树上的边,那么我们因为使用了这条边做最短路,因此我们求得的一定是通过这条边相关的最短距离

因此枚举全部就能获得答案

NC19814 最短路(LCA+思维)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int N=1e5+200;
const int mod=1e9+7;
int h[N],ne[N<<1],e[N<<1],idx,cnt;
bool st[N<<1],pos[N],used[N<<1];
int n,m;
int lg[N<<1];
int depth[N],f[N][25],dis[210][N],from[N<<1],to[N<<1];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa){
    depth[u]=depth[fa]+1;
    st[u]=1;
    f[u][0]=fa;
    int i;
    for(i=1;i<lg[depth[u]];i++){
        f[u][i]=f[f[u][i-1]][i-1];
    }
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(st[j])
            continue;
        used[i]=used[i^1]=1;
        dfs(j,u);
    }
}
void bfs(int s){
    int i;
    cnt++;
    for(i=0;i<=n;i++){
        dis[cnt][i]=0x3f3f3f3f;
        st[i]=0;
    }
    dis[cnt][s]=0;
    queue<int> q;
    q.push(s);
    while(q.size()){
        int t=q.front();
        q.pop();
        if(st[t])
            continue;
        st[t]=1;
        for(i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            if(dis[cnt][j]>dis[cnt][t]+1){
                dis[cnt][j]=dis[cnt][t]+1;
                q.push(j);
            }
        }
    }
}
int lca(int a,int b){
    if(depth[a]<depth[b])
        swap(a,b);
    int i;
    for(i=21;i>=0;i--){
        if(depth[f[a][i]]>=depth[b]){
            a=f[a][i];
        }
    }
    if(a==b)
        return a;
    for(i=21;i>=0;i--){
        if(f[a][i]!=f[b][i]){
            a=f[a][i];
            b=f[b][i];
        }
    }
    return f[a][0];
}
int main(){
    //ios::sync_with_stdio(false);
    memset(h,-1,sizeof h);
    cin>>n>>m;
    int i;
    for(i=1;i<=n;i++)
        lg[i]=lg[i-1]+(i==(1<<lg[i-1]));
    for(i=1;i<=m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        from[idx]=a;
        add(a,b);
        from[idx]=b;
        add(b,a);
    }
    st[0]=1;
    dfs(1,0);
    for(i=0;i<idx;i+=2){
        if(used[i])
            continue;
        used[i]=used[i^1]=1;
        if(!pos[from[i]]){
            pos[from[i]]=1;
            bfs(from[i]);
        }
    }
    int q;
    cin>>q;
    while(q--){
        int a,b;
        scanf("%d%d",&a,&b);
        int ans;
        ans=depth[a]+depth[b]-2*depth[lca(a,b)];
        for(i=1;i<=cnt;i++)
            ans=min(ans,dis[i][a]+dis[i][b]);
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

上一篇:关于opencv3.2的parallel_for_函数不支持bind function的处理(基于ch8代码)


下一篇:在Linux应用程序中打印函数调用栈