Connectionsbetween cities
Time Limit: 10000/5000 MS(Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 12422 Accepted Submission(s): 2875
Problem Description
After World War X, a lot ofcities have been seriously damaged, and we need to rebuild those cities.However, some materials needed can only be produced in certain places. So weneed to transport these materials from city to city. For most of roads had beentotally destroyed during the war, there might be no path between two cities, nocircle exists as well.
Now, your task comes. After giving you the condition of the roads, we want toknow if there exists a path between any two cities. If the answer is yes,output the shortest path between them.
Input
Input consists of multipleproblem instances.For each instance, first line contains three integers n, mand c, 2<=n<=10000, 0<=m<10000, 1<=c<=1000000. n representsthe number of cities numbered from 1 to n. Following m lines, each line hasthree integers i, j and k, represent a road between city i and city j, withlength k. Last c lines, two integers i, j each line, indicates a query of cityi and city j.
Output
For each problem instance, oneline 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 byBJNU
Recommend
gaojie
题目意思是说:给你N个节点,给你M条边,然后C条查询,查询两个点之间的距离。
如果两点不在同一颗树上,那么这两点也就不存在什么距离。这时候输出“Not connected”;
这道题目可以转换成LCA来做。如果人工模拟求两点间距离,也是要从两个点出发向上沿着路走,汇聚到一点。就是这个算法的思想。
两点间距离可以转化为两点到LCA的距离和减去 两倍的LCA到根节点的距离。
#include
#include
#include
#include
#include
#define N 10050*2
using namespace std;
int n,m,num,cnt;
struct node
{
int to,next,cost;
}e[N];
int head[N],dis[N],depth[N];
int pre[N],fa[250][N];
int vis[N];
void init()
{
cnt=0;
for(int i=1;i<=n;i++)//用并查集来查找两点是否在同一颗树上
pre[i]=i;//初始化并查集
memset(e,0,sizeof e);//初始化建边
memset(head,-1,sizeof head);
memset(dis,0,sizeof dis);//初始化树深,距离
memset(depth,0,sizeof depth);
memset(vis,0,sizeof vis);
memset(fa,-1,sizeof fa);
}
int getfa(int x)//并查集
{
if(x==pre[x])
return x;
else
return pre[x]=getfa(pre[x]);
}
void merge(int u,int v)//合并到同一颗树上
{
int t1,t2;
t1=getfa(u);
t2=getfa(v);
if(t1!=t2)
pre[t1]=t2;
}
void addedge(int u,int v,int w)//建边
{
e[cnt].to=u;
e[cnt].cost=w;
e[cnt].next=head[v];
head[v]=cnt++;
}
void dfs(int u,int f)//搜索树,更新距离,树深
{
vis[u]=1;
for(int i=head[u];~i;i=e[i].next)
{
int To=e[i].to;
if(To==f||vis[To]) continue;
dis[To]=dis[u]+e[i].cost;
depth[To]=depth[u]+1;
fa[0][To]=u;
dfs(To,u);
}
}
void solve()//树上倍增法
{
for(int i=1;i<=n;i++)
{
if(!vis[i])
dfs(i,-1);
}
for(int i=0;i+1<15;i++)
{
for(int j=1;j<=n;j++)
if(fa[i][j]<0)
fa[i+1][j]=-1;
else
fa[i+1][j]=fa[i][fa[i][j]];
}
}
int lca(int u,int v)//LCA倍增法在线查询
{
if(depth[u]>depth[v])
swap(u,v);
for(int i=0;i<=15;i++)
{
if((depth[v]-depth[u])>>i&1)
v=fa[i][v];
}
if(u==v)
return v;
for(int i=15;i>=0;i--)
{
if(fa[i][u]!=fa[i][v])
{
u=fa[i][u];
v=fa[i][v];
}
}
return fa[0][v];
}
int main()
{
int i,a,b,c;
while(scanf("%d%d%d",&n,&m,&num)!=EOF)
{
init();
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
addedge(b,a,c);
merge(a,b);
}
solve();
for(int i=1;i<=num;i++)
{
scanf("%d%d",&a,&b);
int t1=getfa(a);
int t2=getfa(b);
if(t1==t2)//在同一颗树上
printf("%d\n",dis[a]+dis[b]-2*dis[lca(a,b)]);
else
printf("Not connected\n");
}
}
return 0;
}