Connections between cities(LCA+并查集)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=2874

Connections between cities

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 15139    Accepted Submission(s): 3449

Problem Description

After World War X, a lot of cities have been seriously damaged, and we need to rebuild those cities. However, some materials needed can only be produced in certain places. So we need to transport these materials from city to city. For most of roads had been totally destroyed during the war, there might be no path between two cities, no circle exists as well.
Now, your task comes. After giving you the condition of the roads, we want to know if there exists a path between any two cities. If the answer is yes, output the shortest path between them.

Input

Input consists of multiple problem instances.For each instance, first line contains three integers n, m and c, 2<=n<=10000, 0<=m<10000, 1<=c<=1000000. n represents the number of cities numbered from 1 to n. Following m lines, each line has three integers i, j and k, represent a road between city i and city j, with length k. Last c lines, two integers i, j each line, indicates a query of city i and city j.

Output

For each problem instance, one line for each query. If no path between two cities, output “Not connected”, otherwise output the length of the shortest path between them.

Sample Input

5 3 2

1 3 2

2 4 3

5 2 3

1 4

4 5

Sample Output

Not connected

6

Hint

Hint Huge input, scanf recommended.

Source

2009 Multi-University Training Contest 8 - Host by BJNU

Recommend

gaojie   |   We have carefully selected several similar problems for you:  2873 2876 2872 2875 2877 

题目:

这道题就是让求任意两点间的距离。然后不在同一个连通分量的话输出“Not connected ”

思路:典型lca的题目。就是中间要加个并查集,判断一下是否在同一个连通分量里。

所以中间一个连通分量一个dfs。

这是我的第一个rmq版的lca的代码。

不知道为什么,maxn要开大两倍才行,但是10000就可以了呀,非要20000,有知道的巨佬可以告诉我原因。。。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=21000+100;
const int maxm=21000+100;
int cnt,num,fa[maxn],head[maxn];
int first[maxn],que[maxn];
int depth[maxn];
int dp[maxn][20];
int dist[maxn];
bool vis[maxn];
struct node{
    int to,next,val;
}G[maxm<<1];
void init(){
    memset(head,-1,sizeof(head));
    memset(vis,false,sizeof(vis));
    cnt=0;
    num=0;
  ///  memset(que,0,sizeof(que));
  ///  memset(first,0,sizeof(first));
  ///  memset(dist,0,sizeof(dist));///这道题独有,表明从根节点到这个点的最短距离
   /// memset(depth,0,sizeof(depth));
}
int Find(int x){
   if(x==fa[x])
        return x;
   else
        return fa[x]=Find(fa[x]);
}
void join(int x,int y){
    x=Find(x);
    y=Find(y);
    if(x==y)
        return ;
    else
        fa[x]=y;
}
void add(int a,int b,int c){
    G[++cnt].to=b;
    G[cnt].val=c;
    G[cnt].next=head[a];
    head[a]=cnt;
}
int dfs(int u,int deep){
    vis[u]=true;///表示是否访问过
    que[++num]=u;///num在此处相当于dfs_clock
    first[u]=num;///表示第一次走的编号
    depth[num]=deep;

    for(int i=head[u];i!=-1;i=G[i].next){
            int v=G[i].to;
            int w=G[i].val;
        if(!vis[v]){
            dist[v]=dist[u]+w;
            dfs(v,deep+1);
            que[++num]=u;
            depth[num]=deep;
        }
    }

}
void ST(int n)
{
    for(int i=1;i<=n;i++)
        dp[i][0] = i;
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i+(1<<j)-1<=n;i++){
            int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1];
            dp[i][j] = depth[a]<depth[b]?a:b;
        }
    }
}
//两个节点之间的路径深度最小的就是LCA
int RMQ(int l,int r)
{
    int k=0;
    while((1<<(k+1))<=r-l+1)
        k++;
    int a = dp[l][k], b = dp[r-(1<<k)+1][k]; //保存的是编号
    return depth[a]<depth[b]?a:b;
}
int LCA(int u ,int v)
{
    int x = first[u] , y = first[v];
    if(x > y) swap(x,y);
    int res = RMQ(x,y);
    return que[res];
}

int main()
{
    int a,b,c;
    int n,m,Q;
    while(~scanf("%d%d%d",&n,&m,&Q)){
        init();
        for(int i=1;i<=n;i++){
            fa[i]=i;
        }///并查集必须要这个初始化
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
            join(a,b);
        }
        for(int i=1;i<=n;i++){
            if(fa[i]==i){
                dist[i]=0;
                dfs(i,1);
            }
        }
        ST(2*n-1);
        while(Q--){
            scanf("%d%d",&a,&b);
           /// cout<<Find(a)<<"    "<<Find(b)<<endl;
            ///cout<<endl;
            if(Find(a)==Find(b)){
                int lca=LCA(a,b);
              ///  cout<<"lca"<<lca<<endl;
               /// cout<<dist[a]<<"  "<<dist[b]<<"   "<<dist[lca]<<endl;
                printf("%d\n",dist[a]+dist[b]-2*dist[lca]);
            }
            else
                printf("Not connected\n");
        }

    }
    return 0;
}

精简版:

#include<bits/stdc++.h>
using namespace std;
const int maxn=21000+100;
const int maxm=21000+100;
int cnt,num,fa[maxn],head[maxn];
int first[maxn],que[maxn];
int depth[maxn];
int dp[maxn][20];
int dist[maxn];
bool vis[maxn];
struct node{
    int to,next,val;
}G[maxm<<1];
void init(){
    memset(head,-1,sizeof(head));
    memset(vis,false,sizeof(vis));
    cnt=0;
    num=0;
}
int Find(int x){
   if(x==fa[x])
        return x;
   else
        return fa[x]=Find(fa[x]);
}
void join(int x,int y){
    x=Find(x);
    y=Find(y);
    if(x==y)
        return ;
    else
        fa[x]=y;
}
void add(int a,int b,int c){
    G[++cnt].to=b;
    G[cnt].val=c;
    G[cnt].next=head[a];
    head[a]=cnt;
}
int dfs(int u,int deep){
    vis[u]=true;///表示是否访问过
    que[++num]=u;///num在此处相当于dfs_clock
    first[u]=num;///表示第一次走的编号
    depth[num]=deep;

    for(int i=head[u];i!=-1;i=G[i].next){
            int v=G[i].to;
            int w=G[i].val;
        if(!vis[v]){
            dist[v]=dist[u]+w;
            dfs(v,deep+1);
            que[++num]=u;
            depth[num]=deep;
        }
    }

}
void ST(int n)
{
    for(int i=1;i<=n;i++)
        dp[i][0] = i;
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i+(1<<j)-1<=n;i++){
            int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1];
            dp[i][j] = depth[a]<depth[b]?a:b;
        }
    }
}
//两个节点之间的路径深度最小的就是LCA
int RMQ(int l,int r)
{
    int k=0;
    while((1<<(k+1))<=r-l+1)
        k++;
    int a = dp[l][k], b = dp[r-(1<<k)+1][k]; //保存的是编号
    return depth[a]<depth[b]?a:b;
}
int LCA(int u ,int v)
{
    int x = first[u] , y = first[v];
    if(x > y) swap(x,y);
    int res = RMQ(x,y);
    return que[res];
}

int main()
{
    int a,b,c;
    int n,m,Q;
    while(~scanf("%d%d%d",&n,&m,&Q)){
        init();
        for(int i=1;i<=n;i++){
            fa[i]=i;
        }///并查集必须要这个初始化
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
            join(a,b);
        }
        for(int i=1;i<=n;i++){
            if(fa[i]==i){
                dist[i]=0;
                dfs(i,1);
            }
        }
        ST(2*n-1);
        while(Q--){
            scanf("%d%d",&a,&b);
            if(Find(a)==Find(b)){
                int lca=LCA(a,b);
                printf("%d\n",dist[a]+dist[b]-2*dist[lca]);
            }
            else
                printf("Not connected\n");
        }

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xianpingping/article/details/81668601