n个点用n-1条边连接,求两个点间的最短路

显然可以想到用floyd预处理,但复杂度过高

所以一些巨发明了LCA

为什么这类最短路问题要找最近公共祖先,这是一个显然的问题,最近公共祖先说简陋了就是在这个“树”上找一个“转折点"

LCA分为离线和在线两种,这里先写在线的方法

在线LCA运用的思想是倍增

何为倍增?

在我这个渣看来,一个正整数是可以写成一个或多个n不相同的2^n的和

那么一些时候就可以依据这一特征进行算法优化,log一下复杂度就大大降低了

具体的代码实现大体分三部分

首先是用邻接表实现的深搜,得到每个点的“深度”(将这个图看成树)

需要注意的是for循环中间i的判断条件与memset初始化的head[]数组值有关

f[edge[i].to][0]记录的值为其父节点

1 void dfs(int p){
2     for(int i=head[p];i;i=edge[i].next){
3         if(!deep[edge[i].to]){
4             deep[edge[i].to]=deep[p]+1;
5             f[edge[i].to][0]=p;
6             dfs(edge[i].to);
7         }
8     }
9 }

接着是对f[][]数组预处理

f[i][j] 表示点i向上走2^j步到达的点p

f[i][j-1] 表示节点i向上走2^(j-1)步到达的节点p'

p'再向“上”走2^j-2^(j-1)=2^(j-1)步则可到达p

所以可以得到递推式f[i][j]=f[f[i][j-1]][j-1]

1 void work(){
2    for(int j=1;(1<<j)<=n;j++)
3         for(int i=1;i<=n;i++)
4             if(f[i][j-1]!=-1)
5                 f[i][j]=f[f[i][j-1]][j-1];
6 }

最后就是LCA核心

这里的i需要单独定义出来

注意依据深度aa和bb,一定要从下向上走的吧

 1 int lca(int aa,int bb){
 2     int i;
 3     if(deep[aa]<deep[bb]) swap(aa,bb);
 4     for(i=0;(1<<i)<=deep[aa];i++);
 5     i--;
 6     for(int j=i;j>=0;j--)
 7         if(deep[aa]-(1<<j)>=deep[bb])
 8             aa=f[aa][j];
 9     if(aa==bb) return aa;
10     for(int j=i;j>=0;j--){
11         if(f[aa][j]!=-1&&f[aa][j]!=f[bb][j]){
12             aa=f[aa][j];
13             bb=f[bb][j];
14         }
15     }
16     return f[aa][0];
17 }

附一模板题

1036 商务旅行

时间限制: 1 s

空间限制: 128000 KB

题目等级 : 钻石 Diamond
题目描述 Description

某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。

假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。

你的任务是帮助该商人计算一下他的最短旅行时间。

输入描述 Input Description

输入文件中的第一行有一个整数N,1<=n<=30 000,为城镇的数目。下面N-1行,每行由两个整数a 和b (1<=ab<=n; a<>b)组成,表示城镇a和城镇b有公路连接。在第N+1行为一个整数M,下面的M行,每行有该商人需要顺次经过的各城镇编号。

输出描述 Output Description

在输出文件中输出该商人旅行的最短时间。

样例输入 Sample Input
5
1 2
1 5
3 5
4 5
4
1
3
2
5

样例输出 Sample Output
7

注意一下f[][]数组赋初值的问题就好
贴代码
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int n=0,x=0,y=0,cnt=0,head[30010],deep[30010],f[30010][33],m=0,a=0,b=0,ans=0;
 7 struct data{
 8     int next,to;
 9 }edge[60010];
10
11 void add(int start,int end){
12     edge[++cnt].next=head[start];
13     edge[cnt].to=end;
14     head[start]=cnt;
15 }
16
17 void dfs(int p){
18     for(int i=head[p];i;i=edge[i].next){
19         if(!deep[edge[i].to]){
20             deep[edge[i].to]=deep[p]+1;
21             f[edge[i].to][0]=p;
22             dfs(edge[i].to);
23         }
24     }
25 }
26
27 void work(){
28    for(int j=1;(1<<j)<=n;j++)
29         for(int i=1;i<=n;i++)
30             if(f[i][j-1]!=-1)
31                 f[i][j]=f[f[i][j-1]][j-1];
32 }
33
34 int lca(int aa,int bb){
35     int i;
36     if(deep[aa]<deep[bb]) swap(aa,bb);
37     for(i=0;(1<<i)<=deep[aa];i++);
38     i--;
39     for(int j=i;j>=0;j--)
40         if(deep[aa]-(1<<j)>=deep[bb])
41             aa=f[aa][j];
42     if(aa==bb) return aa;
43     for(int j=i;j>=0;j--){
44         if(f[aa][j]!=-1&&f[aa][j]!=f[bb][j]){
45             aa=f[aa][j];
46             bb=f[bb][j];
47         }
48     }
49     return f[aa][0];
50 }
51
52 int main(){
53     scanf("%d",&n);
54     memset(head,0,sizeof(head));
55     memset(deep,0,sizeof(deep));
56     memset(f,-1,sizeof(f));
57     for(int i=1;i<n;i++){
58         scanf("%d%d",&x,&y);
59         add(x,y);
60         add(y,x);
61     }
62     deep[1]=1;
63     dfs(1);
64     work();
65
66     scanf("%d",&m);
67     scanf("%d",&a);
68     for(int i=1;i<m;i++){
69         scanf("%d",&b);
70         ans+=deep[a]+deep[b]-2*deep[lca(a,b)];
71         a=b;
72     }
73     printf("%d\n",ans);
74     return 0;
75 }

转载于:https://www.cnblogs.com/sdfzxh/p/6670125.html

倍增LCA code[vs]1036商务旅行相关推荐

  1. codevs——1036 商务旅行

    1036 商务旅行  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果 题目描述 Description 某首都城市的商人要经常到各城镇 ...

  2. [CODEVS 1036]商务旅行

    [问题描述] 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有 ...

  3. 【codevs1036】商务旅行,LCA练习

    商务旅行 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做, ...

  4. 《商务旅行》解题报告

    <商务旅行>解题报告 by mps [题目描述] 某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间. 假设有N个城镇,首都编号为1,商人从首都出发,其 ...

  5. BZOJ 2144 跳跳棋(神仙建模题,倍增 LCA,二分)【BZOJ修复工程】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2144 是 hydro 的 BZOJ ...

  6. [BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)

    4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MB Submit: 2131  Solved: 865 [Submit][Sta ...

  7. HDU - 3078 Network 倍增LCA

    倍增lca,把路径上点全部拉出来拍个序输出第k大就过了. 不知道怎么过的,咱也不敢问. #include<stdio.h> #include<string.h> #includ ...

  8. 洛谷T1967 货车运输 Kruskal最大生成树倍增LCA

    这题的题意是:对于每组x.y,求x到y路径上最小边权的最大值. 于是可以使用最大生成树,因为最大生成树满足性质:生成树中最小边权最大,且任意两点间路径上最小边权最大. 有了树之后,要求路径,那就要考虑 ...

  9. NOIP2013 D1T3 货车运输 倍增LCA OR 并查集按秩合并

    思路: Kruskal求最大生成树+倍增LCA // by SiriusRen #include <cstdio> #include <cstring> #include &l ...

最新文章

  1. 破4!《我想进大厂》之Java基础夺命连环16问
  2. 如何让一滴水不蒸发?
  3. 如果从Silverlight 读取本地GB2312格式的xml文件
  4. python:如何将字典值写入一个文本文件?
  5. TCP listen() Backlog 参数详解
  6. 你还在问android横竖屏切换的生命周期?
  7. #ifndef #define #endif ”防止头文件被重复包 .
  8. 03_FindInPartiallySortedMatrix.cpp
  9. 【python】hashlib.shasha256练习注册 --笔记
  10. jithub使用整理资料
  11. 95-10-110-启动-AdminManager
  12. JAVA多线程售票问题
  13. 互利网上数字金融典型场景: 网络支付
  14. 在vuex的mutations中使用vue的小技巧
  15. incaseformat蠕虫病毒样本分析
  16. matlab2016 wavread,DSP MATLAB软件平台下,利用函数wavread对语音信号进行采样,记住 频率和 点数; 2 238万源代码下载- www.pudn.com...
  17. 机器学习笔记(四)聚类
  18. mysql分组分批_[Mysql]分组取最新一条
  19. web页面设计实训——03.12
  20. 腾讯视频播放内容下载流程

热门文章

  1. [数据结构与算法] 单链表的简单demo
  2. 你真的了解Ioc与AOP 吗?(2)
  3. 了解 Vue SSR 这一篇足以
  4. 跨语言RPC框架Thrift详解
  5. span里面插入文字
  6. react --- 隔代传递参数的三种方式
  7. es6 --- 正确获取Generator函数内部的this对象使其可以使用new
  8. vue --- 使用vue在html上显示当前时间
  9. 深入Java内存模型
  10. MVC架构模式(2)