日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

倍增LCA code[vs]1036商务旅行

發布時間:2023/12/10 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 倍增LCA code[vs]1036商务旅行 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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<=a,?b<=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商务旅行的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。