这个没别的。。。只是记录我学习LCA的历程而已 。。。
/* 写了个有bug的LAC(应该不算), 就是建树搜索的时候必须要以1为节点 ,然后开始搜索(讲道理这个缺陷已经很大了。。。)
算是我实现LAC的第一步吧*/
#include<bits/stdc++.h>
using namespace std ;
vector<int> q[1000 + 5] ;
int s , t ; int n ;
int vis[10500] ;
int pre[10500] ;
int LAC[105500] ;
void init(){
for(int i = 0 ; i <=n ; i++){
pre[i] = i ;
q[i].clear() ;
vis[i] = 0 ;
}
}
int find(int x)
{
return pre[x]==x?pre[x]:pre[x]=find(pre[x]);
}
void Union(int u , int ui){
if(find(u) != find(ui) ) {
pre[ui]=u ;
}
}
/* 树的节点从1开始*/
void solve(int x){
int len = q[x].size() ;
for(int i = 0 ; i < len ; i++){
solve(q[x][i]) ;
Union(x , q[x][i]) ;
// pre[q[x][i]] = x ;
// vis[x] = 1 ;
}
vis[x] = 1 ;
/*if(vis[s] == vis[t] && vis[s] == 1 ){
}*/
if(x == s && vis[t] == 1){
printf("公共祖先为: %d\n" ,find(t) );
}
if(x == t && vis[s] == 1 ){
printf("公共祖先为 %d\n", find(s) ) ;
}
}
int main(){
cin >> n ;
init() ;
for(int i = 0 ; i <n - 1 ; i++){
int u , v ;
cin >> u >> v ;
q[u].push_back(v) ;
// q[v].push_back(u) ;
}
cin >> s >> t ;
solve(1) ;
return 0 ;
}
之后加了个双向边 , 求的也是最近的公共祖先
然后发现,其实对于一棵树,你可以以任何一个节点来作为顶点,
只是这样子做只是树的深度和公共祖先不同而已,如果对于一个无根树
可以以任何点来作为顶点,这样子求两点之间的最短距离其实是一样的。
#include<bits/stdc++.h>
using namespace std ;
vector<int> q[1000 + 5] ;
int s , t ; int n ;
int vis[10500] ;
int pre[10500] ;
int LAC[105500] ;
void init(){
for(int i = 0 ; i <=n ; i++){
pre[i] = i ;
q[i].clear() ;
vis[i] = 0 ;
}
}
int find(int x)
{
return pre[x]==x?pre[x]:pre[x]=find(pre[x]);
}
void Union(int u , int ui){
if(find(u) != find(ui) ) {
pre[ui]=u ;
}
}
/* 树的节点从1开始*/
void solve(int x){
int len = q[x].size() ;
LAC[x] = 1 ;
for(int i = 0 ; i < len ; i++){
if(LAC[q[x][i]] == 0 ){
solve(q[x][i]) ;
Union(x , q[x][i]) ;
}
// pre[q[x][i]] = x ;
// vis[x] = 1 ;
}
vis[x] = 1 ;
/*if(vis[s] == vis[t] && vis[s] == 1 ){
}*/
if(x == s && vis[t] == 1){
printf("公共祖先为: %d\n" ,find(t) );
}
if(x == t && vis[s] == 1 ){
printf("公共祖先为 %d\n", find(s) ) ;
}
}
int main(){
cin >> n ;
init() ;
for(int i = 0 ; i <n - 1 ; i++){
int u , v ;
cin >> u >> v ;
q[u].push_back(v) ;
q[v].push_back(u) ;
}
cin >> s >> t ;
solve(1) ;
return 0 ;
}
学会求公共节点以后,开始求无根树的任意两点距离
然后WA了7,8次后终于AC了。。。
/*我居然没看模板23333333*/
#include<string>
#include<cstring>
#include<iostream>
#include<vector>
#include<cstdio>
using namespace std ;
int n , m ;
const int maxn = 400500;
int head[maxn] ; // 链式前向星
int dis[maxn] ; // 用于记录路径之和(用法; 有头节点一直往下累加 , dis[v] 表示从节点1到v的距离)
int pre[maxn] ; // 并查集函数
int LAC[maxn] ; // 用于记录公共祖先是谁
int _head[maxn] ;
int ans[maxn] , ans1[maxn] ;
int vis[maxn] ; // vis标记 ,因为是双向边,不加vis标记会造成死循环
struct edge{
int to , next , w ;
}edge[maxn ];
struct node{
int to , next , num ;
}st[maxn];
int cnt = 0 , tot = 0;
int find(int x) // 并查集函数
{
if(pre[x]==x) return x;
return pre[x]=find(pre[x]);
}
void init(){
cnt = 0 ;
tot = 0 ;
memset(head , -1 , sizeof(head)) ;
memset(dis , 0 , sizeof(dis)) ;
memset(vis , 0 , sizeof(vis)) ;
memset(_head , -1 , sizeof(_head)) ;
memset(LAC , 0 , sizeof(LAC) ) ;
memset(ans , 0 , sizeof(ans)) ;
memset(ans1 , 0 , sizeof(ans1)) ;
for(int i = 1 ; i <= n ; i++) pre[i] = i ;
}
void add(int u , int v , int w){
edge[++cnt].to = v ;
edge[cnt].w = w ;
edge[cnt].next = head[u] ;
head[u] = cnt ;
}
void add_pro(int u , int v , int num ) {
st[++tot].to = v ;
st[tot].num = num ;
st[tot].next = _head[u] ;
_head[u] = tot ;
}
void solve(int u){
vis[u] = 1 ;
pre[u] = u ; //
for(int i = head[u] ; i != -1 ; i = edge[i].next ){
int v = edge[i].to ;
if(!vis[v]){
dis[v] = edge[i].w + dis[u] ; // 求出1节点到 v节点的距离 (就是这里没注意顺序WA了好多次。。。)
solve(v) ;
pre[v] = u ; // Union函数 因为是树就不需要判断了
// cout << dis[v] <<endl ;
}
}
for(int i = _head[u] ; i != -1 ; i = st[i].next){
int v = st[i].to ;
int num = st[i].num ;
if(vis[v]){
LAC[num] = find(v) ;
// cout << "***" <<endl ;
}
}
}
int main(){
int t ; cin >> t ;
while(t--){
init() ;
scanf("%d %d",&n,&m ) ;
int u , v , w ;
for(int i = 0 ; i < n- 1 ; i++){
scanf("%d %d %d",&u,&v,&w) ;
add(u , v, w ) ;
add(v , u, w ) ;
}
for(int i = 0 ; i < m ; i++){
scanf("%d %d",&u,&v) ;
add_pro(u , v, i) ;
add_pro(v , u, i) ;
ans[i] = u , ans1[i] = v ; // 这个用于记录问题的答案, 因为add_pro这个函数相当于构图
}
solve(1);
/* for(int i = 0 ; i < 10 ; i++){
cout << dis[i] << " " ;
} cout <<endl ;
*/
for(int i = 0 ; i < m ; i++){
// cout << dis[ans[i]] << " " << dis[ans1[i]] << " " <<dis[LAC[i]] << endl ;
printf("%d\n",dis[ans[i]] + dis[ans1[i]] - 2 * dis[LAC[i]]) ;
// 有dis数组的意义来理解
}
}
return 0 ;
}