[問題描述]
某個太空神秘國度中有很多美麗的小村,從太空中可以想見,小村間有路相連,更精確
一點說,任意兩村之間有且僅有一條路徑。小村 a 中有位年輕人愛上了自己村里的美
麗姑娘。每天早晨,姑娘都會去小村 b 裡的麵包房工作,傍晚 6 點回到家。年輕人終
於決定要向姑娘表白,他打算在小村 c 等著姑娘路過的時候把愛慕說出來。問題是,
他不能確定小村 c 是否在小村 b 到小村 a 之間的路徑上。你可以幫他解決這個問題
嗎?
[基本要求]
(1)輸入由若干組測試資料組成。每組資料的第 1 行包含一正整數 n ( l 《 n
《 50000 ) , 代表神秘國度中小村的個數,每個小村即從0到 n - l 編號。接下來有 n -1 行輸入,每行包含一條雙向道路的兩個端點小村的編號,中間用空格分開。之後一行包含一正整數 m ( l 《 m 《 500000
) ,代表著該組測試問題的個數。接下來 m 行,每行給出 a 、 b 、 c 三個小村的編號,中間用空格分開。當 n 為 o 時,表示全部測試結束,不要對該資料做任何處理。
(2)對每一組測試給定的 a 、 b 、c,在一行裡輸出答案,即:如果 c 在 a 和 b 之間的路徑上,輸出 yes ,否則輸出 no.
問題用到最近公共祖先演算法,求c是否在a和b的路徑上
村落分布可抽象化為圖,用鄰接表儲存,定義兩個結構edge和node,edge用於儲存節點的鄰接節點,裡面還有指向下乙個鏈頭節點鄰接節點的指標,node裡面定義了節點的編號,節點的深度(遍歷時初始化,用於尋找最近公共祖先時先使指向深層的節點指標往上跳到與淺層節點指標同一層次),節點的父親陣列fa,儲存該節點路徑上的父親節點。找最近公共祖先的時候,如果兩節點在同一層次時,兩級點相等,那麼該節點就是最近公共節點,否則,設村莊a與村莊b的最近公共祖先為d,a和c的最近公共祖先為ac,b和c的最近公共祖先為bc,如果acc或者bcc,這裡需分情況討論,如果c==d,那麼c就是最近公共祖先,c在ab的路徑上,否則說明c不是a和b的最近公共祖先,c是c和a的最近公共祖先或者是b和c的最近公共祖先,c在ad路徑上或在bd路徑上,如果c並不是a的最近公共祖先並且不是b的最近公共祖先,那麼b不是a和b路徑上的點
lca中倍增法
將2的次冪排成乙個序列,1 、2 、4 、8~,任何數都可以用其中的幾個數相加得到,比如20=16+4,也就是每個正整數都可以拆分成多個2的冪次數。
這樣就可以使兩個結點不再一層一層地往上跳,而是每次都跳2的冪次方層。例如a點要向上跳10層,就可以跳兩次:先跳8層,再跳2層。
有陣列tv[u].fa[i],表示下標為u的節點向上跳2^i 個節點,等於跳了2^(i-1) 個節點再加2^(i-1) 個節點,所以tv[u].fa[i]=tv[tv[u].fa[i-1]].fa[i-1],有了這個結論就可以得到每個節點向上跳2^i 格,這個初始化在bfs中完成,在lca中,先把兩個不同層次的節點跳到同一節點,就運用了倍增思想,先求他兩節點的層次差,用2的次冪表示(本題中用到的處理方法是轉換成二進位制,變數i表示二進位制第幾位,第i位為1則跳到他的第2^ i父親節點那裡,為0則不跳同時i自增,fa[i]是第2^ i個父親),再結合bfs中初始化的各節點儲存的父親陣列,就可以跳到任意下標的節點了
lude
#include
#define height 20
//因為最多有50000個村莊,所以log2(50000)=20
extern
int num, line;
using
namespace std;
typedef
struct edge edge;
typedef
struct node node;
//建立鄰接表
void
creategraph
(node*
& node,
int n)
;//廣度優先遍歷,初始化該圖,找到每個節點的父親和所在的深度
void
bfs(node*
& node,
int root)
;//尋找最近公共祖先
intlca
(node* node,
int u,
int v)
;//判斷節點是否在兩節點的路徑上
void
search
(node* node,
int a,
int b,
int c)
;#include
"lca.h"
int num =
0, line =0;
void
creategraph
(node*
& node,
int n)
cout <<
"請輸入村子的"
<< line <<
"條路"
<< endl;
for(
int i =
0; i < line;
i++)
}void
bfs(node*
& node,
int root)
else}}
}int
lca(node* node,
int u,
int v)
return node[tu]
.fa[0]
;//返回最近公共祖先
}void
search
(node* node,
int a,
int b,
int c)
else
if(ac == c || bc == c)
else
//如果c不是a的祖先,也不是b的祖先,則a和b的路徑上不會經過c點
月亮的愛情故事!
人類給我取名為月亮,把你叫做地球。他們一直弄不明白我倆之間的關係。一些他們叫做科學家的人研究說,你心情的寒暑和情感的潮汐都是因為我,但無法解釋為什麼你能捕獲我這樣巨大的星體做你的衛星。人類一思考,上帝就會發笑。好吧,為了讓人們不要再作無謂的猜測,我決定把這個的秘密說出來。說起來我也曾是一顆行星,在宇...
真實的愛情故事。。。
這篇比較八卦。我好像還沒有八卦過。晚上照例看一下blog訂閱,發現mvm已經到紐約了。預感到,這個傢伙也要開始飄泊了?為什麼說 也 呢?這一期的 申江服務導報 看到一熟人,swing。標題是 高階白領下班化身服務員 夠俗的題目 三個整版。昨天下午還無意間進了boonna,在牆上看到swing在柬埔寨...
真實的愛情故事。。。
這篇比較八卦。我好像還沒有八卦過。晚上照例看一下blog訂閱,發現mvm已經到紐約了。預感到,這個傢伙也要開始飄泊了?為什麼說 也 呢?這一期的 申江服務導報 看到一熟人,swing。標題是 高階白領下班化身服務員 夠俗的題目 三個整版。昨天下午還無意間進了boonna,在牆上看到swing在柬埔寨...