著名的王牌間諜 007 需要執行一次任務,獲取敵方的機密情報。已知情報藏在一個地下迷宮里,迷宮只有一個入口,里面有很多條通路,每條路通向一扇門。每一扇門背后或者是一個房間,或者又有很多條路,同樣是每條路通向一扇門…… 他的手里有一張表格,是其他間諜幫他收集到的情報,他們記下了每扇門的編號,以及這扇門背后的每一條通路所到達的門的編號。007 發現不存在兩條路通向同一扇門。
內線告訴他,情報就藏在迷宮的最深處。但是這個迷宮太大了,他需要你的幫助 —— 請編程幫他找出距離入口最遠的那扇門。
輸入格式:
輸入首先在一行中給出正整數 N(<),是門的數量。最后 N 行,第 i 行(1)按以下格式描述編號為 i 的那扇門背后能通向的門:
K D[1] D[2] ... D[K]
其中 K
是通道的數量,其后是每扇門的編號。
輸出格式:
在一行中輸出距離入口最遠的那扇門的編號。題目保證這樣的結果是唯一的。
輸入樣例:
13 3 2 3 4 2 5 6 1 7 1 8 1 9 0 2 11 10 1 13 0 0 1 12 0 0
輸出樣例:
12
注:本方法還未完善,只是提出想法。實際上有最后一個監測點超時
題意:
可看作給出一樹上所有子節點父節點之間關系,求從頂到底最深的長度。可以通過模擬構建樹的方法做出。
這里我們換一種思路來做。
想法:
易知,最遠的房間一定從沒有下一個房間的結點中出現。反證,若在有下一個房間結點出現,則下一個結點必定比該節點遠。
並且,每個房間的前一個房間已知且唯一,故我們可以記錄所有最后一個房間,然后依次找尋每個房間前一個房間,直到沒有前一個房間,然后
記錄深度。此時最大的深度的房間即為目標門。
以下給出代碼:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int pre[1000005]={0};//用來標記每個房間的前驅,默認進入是的房間無前驅,即為0。 4 int main() 5 { 6 int n,m,a; 7 stack<int> b; 8 scanf("%d",&n); 9 for(int i=1;i<=n;i++) 10 { 11 scanf("%d",&m); 12 if(m==0)b.push(i);//將沒有下一個房間的房間存儲起來。 13 else 14 for(int j=1;j<=m;j++){ 15 scanf("%d",&a); 16 pre[a]=i; 17 } 18 } 19 // for(int i=0;i<=n;i++)cout<<pre[i]<<" "; 20 // cout<<endl; 21 // cout<<b.size()<<endl; 22 int maxi=b.top(),maxx=1; 23 while(b.size()) 24 { 25 a=b.top(); 26 // cout<<b.top()<<endl; 27 int sum=0; 28 while(pre[a]!=0) 29 { 30 sum++; 31 a=pre[a]; 32 } //求出當前房間的深度 33 //cout<<sum<<" "<<a<<endl; 34 if(sum>maxx) 35 { 36 maxx=sum; 37 maxi=b.top(); 38 } //若比前面最深房間深,則更新至當前房間。 39 b.pop(); 40 sum=0; 41 // cout<<maxi<<endl; 42 } 43 printf("%d",maxi); 44 return 0; 45 }
但這段代碼實際上會在最后一個監測點會超時
推測原因:返回時多個不同的房間將相同的路多次返回,如圖所示。

解決思路:
從並查集得到的想法。
用struct構建pre數組,記錄到上一個的距離,默認為1。
當進行一次返回找頂時,先得到深度,再將每個節點pre直接更新為頭部,然后更新該節點深度。這樣在第二次使用時省略的
重復路線。
實現效果如圖:
{這些想法懶得實現了,有時間再說。}