博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
倍增LCA code[vs]1036商务旅行
阅读量:4308 次
发布时间:2019-06-06

本文共 3206 字,大约阅读时间需要 10 分钟。

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<
<=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]
=0;j--) 7 if(deep[aa]-(1<
=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
2 #include
3 #include
4 #include
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<
<=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]
=0;j--) 40 if(deep[aa]-(1<
=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

 

 

 

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

你可能感兴趣的文章
Maven之阿里云镜像仓库配置
查看>>
Maven:mirror和repository 区别
查看>>
微服务网关 Spring Cloud Gateway
查看>>
SpringCloud Feign的使用方式(一)
查看>>
SpringCloud Feign的使用方式(二)
查看>>
关于Vue-cli+ElementUI项目 打包时排除Vue和ElementUI
查看>>
Vue 路由懒加载根据根路由合并chunk块
查看>>
vue中 不更新视图 四种解决方法
查看>>
MySQL 查看执行计划
查看>>
OpenGL ES 3.0(四)图元、VBO、VAO
查看>>
OpenGL ES 3.0(五)纹理
查看>>
OpenGL ES 3.0(八)实现带水印的相机预览功能
查看>>
OpenGL ES 3.0(九)实现美颜相机功能
查看>>
FFmpeg 的介绍与使用
查看>>
Android 虚拟机简单介绍——ART、Dalvik、启动流程分析
查看>>
原理性地理解 Java 泛型中的 extends、super 及 Kotlin 的协变、逆变
查看>>
FFmpeg 是如何实现多态的?
查看>>
FFmpeg 源码分析 - avcodec_send_packet 和 avcodec_receive_frame
查看>>
FFmpeg 新旧版本编码 API 的区别
查看>>
RecyclerView 源码深入解析——绘制流程、缓存机制、动画等
查看>>