Connections between cities

来源:互联网 发布:软件开发部门职责 编辑:程序博客网 时间:2024/06/05 04:07
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 21 3 22 4 35 2 31 44 5
 

Sample Output
Not connected6
Hint
Hint

Huge input, scanf recommended.

题解:典型的LCA离线算法,不过可能有多颗树,需要注意遍历每一颗树,但是又只遍历一次。所以需要用并查集判断询问的两个点是不是同一颗树上的点。

#pragma warning(disable:4996)#include <iostream>#include <cstring>#include <cstdio>#include <vector>using namespace std;struct Node{ int next;int dis;};vector<Node> vec[10001];     //保存邻接点与距离 int ans[10004];              //保存祖先,即并查集中的父节点,判断是不是同一个棵树上 int fa[10004];               // 保存祖先,dfs用 vector<int> q[10001];        //保存询问int p1[1000004];             //第几个询问的第一个城市,下标表示第几个询问 int p2[1000004];             //第二个城市,同上 bool visited[10004];          //访问标记 int d[10004];                //保存该点到根节点距离 int res[1000004];            //保存结果 int find(int x,int* f)   //并查集 {if(x == f[x]){return x;}return f[x] = find(f[x],f);}void dfs(int x,int pre,int dis)  //{fa[x] = x;                  //更新父节点 visited[x] = true;      d[x] = dis;                 //保存该点到根的距离 int k;for(int i = 0;i < vec[x].size();i++){k = vec[x][i].next;if(!visited[k])    {dfs(k,x,dis + vec[x][i].dis);}}for(int i = 0;i < q[x].size();i++)   //找出询问中与该点有关的 {k = (x == p1[q[x][i]] ? p2[q[x][i]] : p1[q[x][i]]);if(-1 == fa[k])       //表示另外一点访问过,那么最近祖先就是另外一点的祖先 {continue;}res[q[x][i]] = d[x] + d[k] - 2 * d[find(k,fa)];  //res保存第i个询问 }fa[x] = find(pre,fa);        //更新该点的父节点 }int main(){int n,m,c;int u,v,dis;Node t1,t2;while(scanf("%d%d%d",&n,&m,&c) != EOF){for(int i = 1;i <= n;i++)        //祖先指向自己 {ans[i] = i;}for(int i = 0;i < m;i++)   //读取每一条边 {scanf("%d%d%d",&u,&v,&dis);t1.next = u;t1.dis = dis;t2.next = v;t2.dis = dis;vec[u].push_back(t2);vec[v].push_back(t1);int x = find(u,ans);        //并查集,用来判断是不是同一棵树上的点 int y = find(v,ans);ans[x] = y;}for(int i = 1;i <= c;i++)   //将每一个访问顺序放入q,dfs时直接通过p1,p2找到另外一个询问点 {scanf("%d%d",&p1[i],&p2[i]);q[p1[i]].push_back(i); q[p2[i]].push_back(i);}memset(fa,-1,sizeof(fa));memset(visited,false,sizeof(visited));memset(res,-1,sizeof(res));for(int i = 1;i <= n;i++) //遍历每一颗树 {if(!visited[i])      //如果没访问过说明该节点所在的树未被访问 {dfs(i,i,0);}}for(int i = 1;i <= c;i++)  //输出结果 {if(find(p1[i],ans) != find(p2[i],ans))  //切记这里不能用ans[p1[i] == ans[p2[i], {                                       //因为可能他们祖先一样但是由于没有更新导致不一样 printf("Not connected\n");          //我在这里错误浪费了几个小时,提交10次左右wa }else{printf("%d\n",res[i]);}}for(int i = 1;i <= n;i++)         //很重要 {vec[i].clear();q[i].clear();}}return 0;}


0 0