CCF——網絡延時(樹的直徑)

題目:

問題描述
  給定一個公司的網絡,由n臺交換機和m臺終端電腦組成,交換機與交換機、交換機與電腦之間使用網絡連接。交換機按層級設置,編號爲1的交換機爲根交換機,層級爲1。其他的交換機都連接到一臺比自己上一層的交換機上,其層級爲對應交換機的層級加1。所有的終端電腦都直接連接到交換機上。
  當信息在電腦、交換機之間傳遞時,每一步只能通過自己傳遞到自己所連接的另一臺電腦或交換機。請問,電腦與電腦之間傳遞消息、或者電腦與交換機之間傳遞消息、或者交換機與交換機之間傳遞消息最多需要多少步。
輸入格式
  輸入的第一行包含兩個整數n, m,分別表示交換機的臺數和終端電腦的臺數。
  第二行包含n - 1個整數,分別表示第2、3、……、n臺交換機所連接的比自己上一層的交換機的編號。第i臺交換機所連接的上一層的交換機編號一定比自己的編號小。
  第三行包含m個整數,分別表示第1、2、……、m臺終端電腦所連接的交換機的編號。
輸出格式
  輸出一個整數,表示消息傳遞最多需要的步數。
樣例輸入
4 2
1 1 3
2 1
樣例輸出
4
樣例說明
  樣例的網絡連接模式如下,其中圓圈表示交換機,方框表示電腦:

  其中電腦1與交換機4之間的消息傳遞花費的時間最長,爲4個單位時間。
樣例輸入
4 4
1 2 2
3 4 4 4
樣例輸出
4
樣例說明
  樣例的網絡連接模式如下:

  其中電腦1與電腦4之間的消息傳遞花費的時間最長,爲4個單位時間。
評測用例規模與約定
  前30%的評測用例滿足:n ≤ 5, m ≤ 5。
  前50%的評測用例滿足:n ≤ 20, m ≤ 20。
  前70%的評測用例滿足:n ≤ 100, m ≤ 100。
  所有評測用例都滿足:1 ≤ n ≤ 10000,1 ≤ m ≤ 10000。

思路: 

         計算樹的直徑問題,兩邊搜索

         第一遍找直徑的一個端點,第二遍通過這個端點搜索出直徑及另一個端點;

        簡單證明(也可以看看這個證明樹的直徑(最長路)的詳細證明

         首先先說明,在樹中任意兩點之間的路徑有且只有一條 ,  dis(x,y)表示 x 到 y 的距離;

         設想 x 和 y 分別爲直徑的兩個端點,a 爲樹上任意一點;

                     假設從 a 搜索找到的最遠的點爲 b(b是除 x,y,a 後任意一點),

                     1.若從 a 到 b 的路徑上與直徑有交點 c,如下圖;

                                             

                           由於 a 到 y 只有 1 條路徑爲 a->c->y, 故  dis(a,b) =  dis(a,c)+dis(c,b) > dis(a,c) + dis(c,y) = dis(a,y)

                                                                                    繼而有  dis(c,b) > dis(c,y)   ==> dis(x,c)+dis(c,b) > dis(x,c) + dis(c,y) 

                                                                                                                  即 dis(x,b) > dis(x,y) , x->y 不是最長的,矛盾,故假設不成立;

                         2.若從 a 到 b 的路徑上與直徑無交點,c 爲直徑上一點,如下圖;

                                  

                                     易有       dis(a,b)  > dis(a,c)+dis(c,y) (距離a的最遠點爲b)

                                     顯然有   dis(a,b)+dis(a,c) > dis(c,y)  即 dis(c,b) > dis(c,y)

                                     所以       dis(x,c)+dis(c,b) > dis(x,c) + dis(c,y)

                                       故 x->y 不是最長路徑,矛盾,假設不成立;

                                       綜上 b 一定是 x,y 中的一點


代碼

#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
#define MAX 21007
vector<int> a[MAX];  //鄰接表 
int pos,mc;  // 遠的點和最遠距離 
bool b[MAX];    //標記是否遍歷過 

//深度優先搜索整張圖,記錄下距離begin最遠的點和其距離 
void dfs(int begin,int c){
    //更新最遠點 
	if(c > mc){
		mc=c;
		pos=begin;
	}
	//繼續往下搜索 
	for(int i=0;i<a[begin].size();++i){
		if(b[a[begin][i]] == false){
			b[a[begin][i]]=true;
			dfs(a[begin][i],c+1);
		}
	}
}

int main(){
    int n,m;
	cin>>n>>m;
    for(int i=2,j;i<=n+m;++i){
    	cin>>j;
    	a[j].push_back(i);
    	a[i].push_back(j);
    }
    //第一遍DFS,找圖的直徑的一端 
    mc=0,pos=0;
    memset(b,0,sizeof(b));
    dfs(n+m,0);
    //第二遍BFS,直到直徑的一段後,搜索另一端,並記錄直徑的長度 
    mc=0;
    memset(b,0,sizeof(b));
    dfs(pos,0);
    
    cout<<mc<<endl;
	return 0;
}


                             

                                          

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章