1. 程式人生 > >[ACM] hihocoder 1062 最近公共祖先·一 (一般做法)

[ACM] hihocoder 1062 最近公共祖先·一 (一般做法)

描述

小Ho最近發現了一個神奇的網站!雖然還不夠像58同城那樣神奇,但這個網站仍然讓小Ho樂在其中,但這是為什麼呢?

“為什麼呢?”小Hi如是問道,在他的觀察中小Ho已經沉迷這個網站一週之久了,甚至連他心愛的樹玩具都棄置一邊。

“嘿嘿,小Hi,你快過來看!”小Ho招呼道。

“你看,在這個對話方塊裡輸入我的名字,在另一個對話方塊裡,輸入你的名字,再點這個查詢按鈕,就可以查出來……什麼!我們居然有同一個祖祖祖祖祖爺爺?”

“誒,真是誒……這個網站有點厲害啊。”小Hi不由感嘆道。

“是啊,這是什麼演算法啊,這麼厲害!”小Ho也附和道。

“別2,我說的是他能弄到這些資料很厲害,而人類的繁殖樹這種層數比較淺的樹對這類演算法的要求可是簡單的不得了,你都能寫出來呢!”小Hi道。

“啊?我也能寫出來?可是……該從哪開始呢?”小Ho困惑了。

小Ho要面臨的問題是這樣的,假設現在他知道了N個人的資訊——他們的父親是誰,他需要對於小Hi的每一次提問——兩個人的名字,告訴小Hi這兩個人的是否存在同一個祖先,如果存在,那麼他們的所有共同祖先中輩分最低的一個是誰?

輸入

每個測試點(輸入檔案)有且僅有一組測試資料。

每組測試資料的第1行為一個整數N,意義如前文所述。

每組測試資料的第2~N+1行,每行分別描述一對父子關係,其中第i+1行為兩個由大小寫字母組成的字串Father_i, Son_i,分別表示父親的名字和兒子的名字。

每組測試資料的第N+2行為一個整數M,表示小Hi總共詢問的次數。

每組測試資料的第N+3~N+M+2行,每行分別描述一個詢問,其中第N+i+2行為兩個由大小寫字母組成的字串Name1_i, Name2_i,分別表示小Hi詢問中的兩個名字。

對於100%的資料,滿足N<=10^2,M<=10^2, 且資料中所有涉及的人物中不存在兩個名字相同的人(即姓名唯一的確定了一個人)。

輸出

對於每組測試資料,對於每個小Hi的詢問,輸出一行,表示查詢的結果:如果根據已知資訊,可以判定詢問中的兩個人存在共同的祖先,則輸出他們的所有共同祖先中輩分最低的一個人的名字,否則輸出-1。

樣例輸入
11
JiaYan JiaDaihua
JiaDaihua JiaFu
JiaDaihua JiaJing
JiaJing JiaZhen
JiaZhen JiaRong
JiaYuan JiaDaishan
JiaDaishan JiaShe
JiaDaishan JiaZheng
JiaShe JiaLian
JiaZheng JiaZhu
JiaZheng JiaBaoyu
3
JiaBaoyu JiaLian
JiaBaoyu JiaZheng
JiaBaoyu LinDaiyu
樣例輸出
JiaDaishan
JiaZheng
-1

解題思路:

小Hi道:“這個問題也應該是樹結構許許多多問題中頗為經典的一個了,如果就簡單的將父子關係視作樹結構中的父子結點關係的話,這個問題其實就是在問樹中兩個結點層數最高的公共祖先——也就是所謂的最近公共祖先,而這個問題有非常多的解決方法,分別適合於不同的場景,像線上演算法離線演算法什麼的現在說給你聽你也不一定能夠很快理解。”

“但是……你不是說我能夠寫出來的麼?”小Ho納悶了。

“所以說我們慢慢來不要急,先教你個最簡單的法子。”小Hi如是說道。

“最簡單的法子……如果資料量不大的話,我完全可以直接將這兩個人的祖先全部找出來,然後取它們的交集,然後再找到其中輩分最低的一個不就行了。”小Ho思考了會這般說道。

小Hi點了點頭道:“差不多就是這樣!當然你也先將一個人的祖先全都標記出來,然後順著另一個的父親一直向上找,直到找到第一個被標記過的結點,便是它們的最近公共祖先結點了。”

“原來這麼簡單!”小Ho笑道:“那我先去寫著了。”

程式碼:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <map>
using namespace std;

const int maxn=202;
bool vis[maxn];
map<string,int>mp;
int parent[maxn];
int tot=0;
int n,m;
string father,son;

int hash(string str)//給字串編號
{
    if(mp.count(str))
        return mp[str];
    else
    {
        mp[str]=++tot;
        return tot;
    }
}

void dfs(int son)//包括son節點在內的所有其祖先節點標記
{
    vis[son]=1;
    if(parent[son]==0)
        return;
    dfs(parent[son]);
}

int dfs2(int son)//找包括son節點在內的其所有其祖先節點中第一個被標記的節點
{
    if(vis[son]==1)
        return son;
    if(parent[son]==0)
        return -1;
    if(vis[parent[son]]==1)
        return parent[son];
    dfs2(parent[son]);
}

string output(int num)//根據編號輸出
{
    map<string,int>::iterator i;
    for(i=mp.begin();i!=mp.end();i++)
    {
        if(i->second==num)
            return i->first;
    }
}

int main()
{
    cin>>n;
    memset(parent,0,sizeof(parent));
    while(n--)
    {
        cin>>father>>son;
        parent[hash(son)]=hash(father);
    }
    cin>>m;
    string a1,a2;
    while(m--)
    {
        memset(vis,0,sizeof(vis));
        cin>>a1>>a2;
        dfs(hash(a1));
        int ans=dfs2(hash(a2));
        if(ans==-1)
            cout<<-1<<endl;
        else
            cout<<output(ans)<<endl;
    }
    return 0;
}

相關推薦

[ACM] hihocoder 1062 最近公共祖先· (一般做法

描述 小Ho最近發現了一個神奇的網站!雖然還不夠像58同城那樣神奇,但這個網站仍然讓小Ho樂在其中,但這是為什麼呢? “為什麼呢?”小Hi如是問道,在他的觀察中小Ho已經沉迷這個網站一週之久了,甚至連他心愛的樹玩具都棄置一邊。 “嘿嘿,小Hi,你快過來看!”小Ho招呼道

#1062 : 最近公共祖先·

輸入 每個測試點(輸入檔案)有且僅有一組測試資料。 每組測試資料的第1行為一個整數N,意義如前文所述。 每組測試資料的第2~N+1行,每行分別描述一對父子關係,其中第i+1行為兩個由大小寫字母組成的字串Father_i, Son_i,分別表示父親的名字和兒子的

hihoCoder week13 最近公共祖先·

祖先 () 搜索 另一個 get div end ace n) 用的dfs,自下往上搜索一個節點的所有祖先,然後在相應祖先 判斷是否是另一個節點的祖先,如果是 就截止,否則繼續往上搜索,直到搜索到,或者知道所有的祖先都被掃描完成 #include <bits/s

最近公共祖先· HihoCoder

#include<bits/stdc++.h> using namespace std; int n,m; map<string,string > pre; void FindAnscetor(string str1,string str2

HihoCoder 1067 最近公共祖先·二

信息 dep 字符串 log i+1 ++ 緊急 next fat 最近公共祖先·二 時間限制:10000ms 單點時限:1000ms 內存限制:256MB 描述 上上回說到,小Hi和小Ho用非常拙劣——或者說粗糙的手段山寨出了一個神奇的網站,這個網站可以計算

hihoCoder week17 最近公共祖先·三 lca st表

col cin mes map ons ini include name pan 記錄dfs序列,dfn[tot] 記錄第tot次訪問的節點 然後查兩點在dfs序中出現的第一次 id[u] id[v] 然後 找 dep[k] = min( dep[i] ) {i 屬於

hihoCoder week17 最近公共祖先·三 lca st表

記錄dfs序列,dfn[tot] 記錄第tot次訪問的節點 然後查兩點在dfs序中出現的第一次 id[u] id[v] 然後  找 dep[k] = min( dep[i] ) {i 屬於 [id[u], id[v]]} 最後dfn[k] 就是所求.. 感覺弄來弄去 就是 在對映... 無非

[HihoCoder]#1067 : 最近公共祖先·二

華電北風吹 天津大學認知計算與應用重點實驗室 2016-06-24 題目分析: 目前程式碼超時,需要改進。 // problem1067.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #includ

hihoCoder 1067 : 最近公共祖先·二(map+離線Tarjan演算法

【思路分析】離線演算法是把所有的詢問先儲存起來,然後在深搜的過程中計算結果。本題本來就是一棵有根樹,應該先計算根節點是多少,然後再從根節點進行深搜。實現為+深搜+並查集。 【AC程式碼】 #

hihocoder 1067 最近公共祖先·二 並查集+stl

題目連結: 題解思路: 面對10^5個 名字和10^5條詢問,肯定要用到特殊的方法: 1.把所有的詢問先存下來,然後再遍歷一次整棵樹得到所有答案 2.遍歷的過程中   查詢含當前節點的 所有詢問,然後找到詢問中的另一個節點;檢視另一個節點的狀態。     

[HihoCoder]#1069 : 最近公共祖先·三

華電北風吹 天津大學認知計算與應用重點實驗室 2016-06-24 題目分析: // problem1069.cpp : 定義控制檯應用程式的入口點。 // #1069 : 最近公共祖先·三 // 張正義 2016-06-20 #incl

hihoCoder_#1062_最近公共祖先·

描述 小Ho最近發現了一個神奇的網站!雖然還不夠像58同城那樣神奇,但這個網站仍然讓小Ho樂在其中,但這是為什麼呢? “為什麼呢?”小Hi如是問道,在他的觀察中小Ho已經沉迷這個網站一週之久了,甚至連他心愛的樹玩具都棄置一邊。 “嘿嘿,小Hi,你快過來看!”小Ho招呼道。 “你看,在這個對話方塊裡輸入我的名

洛谷3379 最近公共祖先模板(倍增

#include<iostream> #include<cstdio> #include<cstring> #define maxn 500010 #define S

多叉樹最近公共祖先問題(LCA

任務:設計一個演算法,對於給定的樹中兩結點,返回它們的最近公共祖先 輸入:第1行有一個正整數n,表示給定的樹有n個結點。結點編號為1,2,3,...,n,編號為1的頂點是樹根。接下來n行中,第i+1行描述了第i個結點的兒子情況。每行的第一個正整數k表示該結點有k個兒子,其後

最近公共祖先·三 HihoCoder

#include<bits/stdc++.h> using namespace std; #define maxn 110000 int n,k,q,sum; int deep[110001],tot; int head[110001],dp[1100

一般二叉樹求最近公共祖先(最簡單的程式碼

當遍歷到一個root點的時候, 1.判斷root是不是null如果root為null,那麼就無所謂祖先節點,直接返回null就好了 2.如果root的左子樹存在p,右子樹存在q,那麼root肯定就是最近祖先 3.如果pq都在root的左子樹,那麼就需要遞迴

tarjan算法求最近公共祖先

技巧 splay 路徑壓縮 tor 沒有 blog 分析 father mar tarjian算法 LCA: LCA(Least Common Ancestor),顧名思義,是指在一棵樹中,距離兩個點最近的兩者的公共節點。也就是說,在兩個點通往根的道路上,肯定會有公共的節

[轉]LCA 最近公共祖先

log 比較 下一步 個人 idt 合並函數 orz ref tle 原文傳送門orzJVxie Tarjan(離線)算法的基本思路及其算法實現     首先是最近公共祖先的概念(什麽是最近公共祖先?):     在一棵沒有環的樹上,每個節點肯定有其父親節點和祖先節點

lca(洛谷P3379 最近公共祖先(LCA

int arc pragma rpi == 代碼 輸出 () div 如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先. 輸入格式: 第一行包含三個正整數N、M、S,分別表示樹的結點個數、詢問的個數和樹根結點的序號。 接下來N-1行每行包含兩個正整數x、y

二叉樹最近公共祖先

ret highlight 筆試 代碼 light brush 二叉 init blog 給定一棵二叉樹,找到兩個節點的最近公共父節點(LCA)。最近公共祖先是兩個節點的公共的祖先節點且具有最大深度。 樣例:對於下面這棵二叉樹 4 / \3 7 / \ 5