Connections between cities

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

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

题意:给你n给点,m条边,有c次询问,每次询问u,v两个点,你需要判断u,v是否连通,u,v的最短距离是多少。

::对于是否连通直接用并查集就可以了,对于连通的两个点最短距离怎么求呢。

数据很大,不允许每次询问都跑一次最短路的算法,那么就考虑一下一劳永逸的办法,有没有办法经过预处理,每次询问都能快速给出答案。

注意到这是无环图,可以转化成树的做法。

对于单个连通分量随意取一点,令其为根,进行dfs遍历,得到每个点到根结点的距离,保存起来(我这里用dis保存),并且得到一个dfs遍历的序列,求出每两个点的lca。如何求lca具体看

lca –> rmq. 那么对于询问在同一个连通分量的两个的距离dis(u->v) = dis(u)+dis(v)-2*dis(lca(u,v));//u到根结点的距离+v到根结点的距离-(u,v)最早公共祖先到根结点的距离的2倍

LCA转RMQ

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = ;
int n, m, Q, fa[N], dis[N];
int id[N], fid[N], gid;
int pos, R[N], E[N<<], d[N<<][];
bool vis[N]; struct edge {
int u, v, w, next;
edge() {}
edge(int u, int v, int w, int next):u(u),v(v),w(w),next(next) {}
}e[N<<];
int ecnt, head[N]; inline void add(int u, int v, int w) {
e[ecnt] = edge(u, v, w, head[u]);
head[u] = ecnt++;
} int find(int x){
return x == fa[x] ? x : fa[x] = find(fa[x]);
} void dfs(int u, int dep){
id[u] = ++gid;
fid[gid] = u;
R[u] = ++pos;
E[pos] = id[u]; //保存dfs序列,求RMQ(lca) dis[u] = dep; // 结点u到根结点的距离
vis[u] = ;
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].v;
if(vis[v]) continue;
dfs(v, dep + e[i].w);
E[++pos] = id[u];
}
} void init_RMQ() {
for(int i = ; i <= pos; ++i) d[i][] = E[i];
for(int j = ; (<<j) <= pos; ++j) {
for(int i = ; i + (<<j) - <= pos; ++i) {
d[i][j] = min(d[i][j-], d[i + (<<(j-))][j-]);
}
}
} inline int RMQ(int L, int R) {
if(L>R) swap(L, R);
int k = ;
while(<<(k + ) <= R - L + ) ++k;
return min(d[L][k], d[R-(<<k)+][k]);
} void solve(){
ecnt = ; gid = , pos = ;
for(int i = ; i <= n; ++i) {
head[i] = -;
fa[i] = i;
} int u, v, w;
for(int i = ; i < m; ++i) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
u = find(u), v = find(v);
fa[u] = v;
} memset(vis, , sizeof(vis));
for(int i = ; i <= n; ++i) {
if(!vis[i]) dfs(i, ); //对于每个连通块取一个根结点
}
init_RMQ(); int lca, ans;
while(Q--){
scanf("%d%d", &u, &v);
if(find(u) != find(v)) {
puts("Not connected");
}
else {
lca = fid[ RMQ(R[u], R[v]) ];
ans = dis[u] + dis[v] - *dis[lca];
printf("%d\n", ans);
}
}
} int main()
{
// freopen("in.txt", "r", stdin);
while(scanf("%d%d%d", &n, &m, &Q)>) solve();
return ;
}

tarjan离线算法

view code#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1e4+10;
const int maxc=1e6+10;
struct node{
int to,w;
node(int a=0,int b=0){to=a;w=b;}
};
int f[maxn],dis[maxn],n,ans[maxc],vis[maxn],mark[maxn];
//f[i]并查集所用,记录前继结点
//dis[i]记录个点到跟结点的距离
//ans记录m个询问的答案
//vis标记查询过了的点
//mark记录已访问过的根节点。由于已遍历的树所有结点的find都是根节点,这样就能判断下是否在别的树里了
vector<node>e[maxn];//记录树
vector<node>q[maxn];//记录所求最短距离的两点
int find(int x)
{
if(x!=f[x])f[x]=find(f[x]);
return f[x];
}
void lca(int u)
{
int i,j,k,v,c;
for(j=0;j<q[u].size();j++)
{
c=q[u][j].to;
//如果所求两点中的对应点已知,则必定在同一子树上,由于并查集只记录所在子树。所以find(c),就是最近公共祖先
if(vis[c]&&ans[q[u][j].w]==-1&&mark[find(c)]!=1)
{
//cout<<f[c]<<"***"<<endl;
ans[q[u][j].w]=dis[u]+dis[c]-2*dis[find(c)];
}
}
for(i=0;i<e[u].size();i++)
{
v=e[u][i].to;
if(vis[v])continue;
vis[v]=1;
dis[v]=dis[u]+e[u][i].w;
lca(v);//深度优先搜索
f[v]=u; }
}
int main()
{
int n,m,c;
while(scanf("%d%d%d",&n,&m,&c)!=EOF)
{
int i,j,k,x,y,z;
for(i=1;i<=n;i++)
{
e[i].clear();
q[i].clear();
f[i]=i;
vis[i]=mark[i]=0;
}
memset(ans,-1,sizeof(ans));
for(i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
e[x].push_back(node(y,z));
e[y].push_back(node(x,z));
}
for(i=1;i<=c;i++)
{
scanf("%d%d",&x,&y);
// if(x==y){ans[i]=0;continue;}
q[x].push_back(node(y,i));
q[y].push_back(node(x,i));
}
for(i=1;i<=n;i++)
{
if(!vis[i])
{
vis[i]=1;
dis[i]=0;
lca(i);
mark[i]=1;
}
}
for(i=1;i<=c;i++)
{
if(ans[i]!=-1)
printf("%d\n",ans[i]);
else
printf("Not connected\n");
}
}
return 0;
}
/*
最近公共祖先lca 离线算法/Tarjan算法,用mark标记是否在同一组里。 方法举例说明:
1
/ \
2 3
/ \
4 5
/ /
7 8
/
9
查询(4,9):到4时,由于vis[9]=0,所以继续;到9后,最近公共祖先就是f[4]=4(回溯的时候记录父节点);
查询(9,8):深度优先搜索,所以到8时才询问;要到8必须回溯到2,在进到8这个子树,所以以记录f[9]=7;f[7]=4;f[4]=2;f[2]=2;所以find(2)=2;
查询(8,3):跟上条相似,必须回溯1才能到3,而find(8)=1就是最近公共祖先;
我们可以发现,对于查询的两点,都要在先查询到的点开始,回溯到最近公共祖先,才查询相对应的点。这也就是离线算法的思路了。。

hdu 2874 Connections between cities [LCA] (lca->rmq)的更多相关文章

  1. hdu 2874 Connections between cities(st&rmq LCA)

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  2. HDU 2874 Connections between cities(LCA)

    题目链接 Connections between cities LCA的模板题啦. #include <bits/stdc++.h> using namespace std; #defin ...

  3. HDU 2874 Connections between cities(LCA离线算法实现)

    http://acm.hdu.edu.cn/showproblem.php?pid=2874 题意: 求两个城市之间的距离. 思路: LCA题,注意原图可能不连通. 如果不了解离线算法的话,可以看我之 ...

  4. HDU 2874 Connections between cities(LCA(离线、在线)求树上距离+森林)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874 题目大意:给出n个点,m条边,q个询问,每次询问(u,v)的最短距离,若(u,v)不连通即不在同 ...

  5. HDU 2874 Connections between cities(LCA+并查集)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=2874 [题目大意] 有n个村庄,m条路,不存在环,有q个询问,问两个村庄是否可达, 如果可达则输出 ...

  6. hdu 2874 Connections between cities (并查集+LCA)

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  7. HDU 2874 Connections between cities(LCA Tarjan)

    Connections between cities [题目链接]Connections between cities [题目类型]LCA Tarjan &题意: 输入一个森林,总节点不超过N ...

  8. hdu 2874 Connections between cities 带权lca判是否联通

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

  9. HDU——2874 Connections between cities

    Connections between cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (J ...

随机推荐

  1. C#设计模式——模板方法(Template Method)

    一.概述在软件开发中,对某一项操作往往有固定的算法结构,而具体的子步骤会因为不同的需要而有所不同.如何可以在稳定算法结构的同时来灵活应对子步骤变化的需求呢?二.模板方法模板方法是一种常见的设计模式,它 ...

  2. [CLR via C#]11. 事件

    一. 设计要公开事件的类型 如果类型定义了事件成员,那么类型(或类型实例)就可以通知其他对象发生了一些特定的事情. 例如,Button类提供了一个名为Click的事件.应用程序中的一个或多个对象可能想 ...

  3. How to manage the certificates in the PC

    1.open Run command. 2.enter 'mmc' . 3.Click File, and Add or Remove Snap-in. 4.Select Certificates, ...

  4. 簡單SQL存儲過程實例

    簡單SQL存儲過程實例 摘自:http://blog.csdn.net/libra6956/article/details/5589173 实例1:只返回单一记录集的存储过程. 银行存款表(bankM ...

  5. 分享一些WinForm数据库连接界面UI

    1.动软代码生成器源码中. 2.DevExpress控件包中有类似的界面 3.代码生成器:http://www.csharpwin.com/csharpspace/11666r2577.shtml 4 ...

  6. ASP.NET或WinFrom中获取汉子的拼音首字母

    1.获得一个字符串的每个字的拼音首字母构成所需的字符串 #region  获取首字母 /// <summary>         /// 这个办法是用来获得一个字符串的每个字的拼音首字母构 ...

  7. JMS学习(三)JMS 消息结构之属性及消息体详解

    一.前言 通过上一篇的学习我们知道了消息分为三个部分,即消息头,属性及消息体,并对消息头的十个属性进行了详细的介绍,本文再对消息属性及消息体进行详细的介绍. 二.属性介绍 消息属性的主要作用是可以对头 ...

  8. YII页面跳转

    $criteria = new CDbCriteria; $criteria->select = array('ziduan"); $res = Model::model()-> ...

  9. 探索HashMap实现原理及其在jdk8数据结构的改进

    因为网上已经太多的关于HashMap的相关文章了,为了避免大量重复,又由于网上关于java8的HashMap的相关文章比较少,至少我没有找到比较详细的.所以才有了本文. 本文主要的内容: 1.Hash ...

  10. windbg定位死锁

    操作系统对死锁的描述如下: 所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去. 那么为什么会产生死锁呢? 1.因为系统资源不足. ...