倍增LCA code[vs]1036商务旅行
来源:互联网 发布:mac选择office安装路径 编辑:程序博客网 时间:2024/06/06 03:00
显然可以想到用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
某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。
假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。
你的任务是帮助该商人计算一下他的最短旅行时间。
输入文件中的第一行有一个整数N,1<=n<=30 000,为城镇的数目。下面N-1行,每行由两个整数a 和b (1<=a, b<=n; a<>b)组成,表示城镇a和城镇b有公路连接。在第N+1行为一个整数M,下面的M行,每行有该商人需要顺次经过的各城镇编号。
在输出文件中输出该商人旅行的最短时间。
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 }
- 倍增LCA code[vs]1036商务旅行
- CODE[VS] 1036 商务旅行(LCA + BFS)
- 商务旅行 code[vs] 1036
- CODE[VS] 1036商务旅行
- 【LCA 倍增法】【codevs 1036 商务旅行】
- 倍增法lca 入门——CODE[VS] 4605 LCA
- 【基础练习】【倍增LCA】codevs1036 商务旅行题解
- codevs 1036 商务旅行 (lca)
- 1036 商务旅行(lca)
- SSL 1746 商务旅行 树上倍增LCA(模板)
- 1036 商务旅行(LCA例题)
- codevs 1036 商务旅行 (LCA)
- NOIP 2013 CODE[VS] 3287 货车运输 倍增LCA || 暴力LCA + 最大生成树
- NOIP 2013 CODE[VS] 3287 货车运输 倍增LCA + 最大生成树
- NOIP 2013 CODE[VS] 3287 货车运输 倍增LCA + 最大生成树
- CodeVs.1036 商务旅行 ( LCA 最近公共祖先 )
- codevs 1036 商务旅行 LCA 解题报告
- codevs1036 商务旅行 lcs倍增
- java 远程调用及动态代理的应用
- jquery实现轮播图
- PAT程序设计考题——甲级1003(Emergency ) C++实现
- 猥琐的暴搜 NOIP2011 Mayan游戏
- 线段树 hdu1698 Just a Hook
- 倍增LCA code[vs]1036商务旅行
- 线段树 洛谷P1531 I Hate It
- 平衡树之splay BZOJ3224 普通平衡树
- 树状数组 HNOI2002 营业额统计
- 树状数组 NOIP2013 火柴排队
- 最小生成树 HZOI 2016公路修建
- 动态规划入门 COGS1398 最长上升子序列
- 动态规划入门 P1115 最大子段和(链状)
- 动态规划入门 TYVJ 1305 最大子段和(环状)