CSP Week6 ProblemA 樹的直徑確定+樹內搜索

CSP 求解樹內直徑和樹內搜索

知識概述

在求解圖論問題時,我們經常會遇到需要求解一個聯通無環圖–樹結構的直徑(在樹圖內相隔距離最遠的兩個點)。
如該圖所示,如果我們要確定直徑,可以按照下述的順序進行求解:
1、找到任意一個點,並從這個點出發找到距離他最遠的點point1
(圖中從帶有箭頭的節點出發,找到最遠點黃點)
2、從這個黃點出發,找出距離它最遠的點。即爲point2。
(圖中黃點出發,幾個紅點都是距離最遠點)
3、point1–point2即爲兩個直徑兩個端點,樹的直徑不唯一
在這裏插入圖片描述

題目概述

實驗室裏原先有一臺電腦(編號爲1),最近氪金帶師咕咕東又爲實驗室購置了N-1臺電腦,編號爲2到N。每臺電腦都用網線連接到一臺先前安裝的電腦上。但是咕咕東擔心網速太慢,他希望知道第i臺電腦到其他電腦的最大網線長度,但是可憐的咕咕東在不久前剛剛遭受了宇宙射線的降智打擊,請你幫幫他。
在這裏插入圖片描述提示: 樣例輸入對應這個圖,從這個圖中你可以看出,距離1號電腦最遠的電腦是4號電腦,他們之間的距離是3。 4號電腦與5號電腦都是距離2號電腦最遠的點,故其答案是2。5號電腦距離3號電腦最遠,故對於3號電腦來說它的答案是3。同樣的我們可以計算出4號電腦和5號電腦的答案是4.

INPUT&輸入樣例

輸入文件包含多組測試數據。對於每組測試數據,第一行一個整數N (N<=10000),接下來有N-1行,每一行兩個數,對於第i行的兩個數,它們表示與i號電腦連接的電腦編號以及它們之間網線的長度。網線的總長度不會超過10^9,每個數之間用一個空格隔開。
輸入樣例:

5
1 1
2 1
3 1
1 1

OUTPUT&輸出樣例

對於每組測試數據輸出N行,第i行表示i號電腦的答案 (1<=i<=N).
輸出樣例;

3
2
3
4
4

題目重述

根據題目中所給定的條件,有N個點,N-1條邊,且整個網絡系統聯通可知這是一棵樹形結構,不存在環。現要求取每個點到其他點的最遠距離,且圖爲無權無向圖,邊權均爲1.

思路解析

在一個樹形結構內,要求取距離其他點的最遠距離,經過簡單的分析可知–等效於求取距離樹的兩個端點的距離,即距離樹直徑端點的距離。
因此可以將問題轉化爲,在樹圖內求取兩個端點,分別求出兩個端點到每個點的距離,比較取最大值即可完成求解。

總結

一道比較明顯的樹形結構問題,如果每個點進行求取時間複雜度比較高。所以可以轉換思維,分別求出兩個端點後,求出兩個端點到各店的距離,比較大小選較大值即可。

題目源碼

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int flag=1e5+1;
struct Edge
{
    int start;//起點
    int end;//終點
    int nxt;//下一條邊的編號
    int value;
}Edges[flag];//邊集
int Map[flag];//前向星數組
int key;//邊數
void init(int point_number)
{
    key=0;
    for(int i=1;i<=point_number;i++)
    Map[i]=-1;
}
void addEdge(int x,int y,int z)
{
    Edges[key].start=x;
    Edges[key].end=y;
    Edges[key].value=z;
    Edges[key].nxt=Map[x];
    Map[x]=key;
    key++;
}
int max_length[flag];
int vis[flag];//訪問數組
int max_point=0;
int maxLength=0;
queue<int> q;   
int pointNumber=0;
void BFS(int x)
{
    for(int i=0;i<=pointNumber;i++)
    {
        vis[i]=0;
        max_length[i]=0;
    }
    max_point=0;
    maxLength=0;
    q.push(x);
    vis[x]=1;
    while(!q.empty())
    {
        int vis_flag=0;//該點的邊訪問指針
        int head=q.front();//該點的一個哨兵,方便後面計算length,指向這個點
        vis_flag=Map[q.front()];
        q.pop();
        while (vis_flag!=-1)//有下一條邊訪問
        {
            if(vis[Edges[vis_flag].end]==0)//沒訪問過
            {
                q.push(Edges[vis_flag].end);
                vis[Edges[vis_flag].end]=1;//標爲訪問過
                max_length[Edges[vis_flag].end]=max_length[head]+Edges[vis_flag].value;//更新距離
                if(max_length[Edges[vis_flag].end]>maxLength)
                {
                    maxLength=max_length[Edges[vis_flag].end];
                    max_point=Edges[vis_flag].end;
                }
            }
            vis_flag=Edges[vis_flag].nxt;
        }
    }
}
int point1_dis[flag];
int point2_dis[flag];
void copy_dis1()
{
	for(int i=1;i<=pointNumber;i++)
	point1_dis[i]=0;
	for(int i=1;i<=pointNumber;i++)
    point1_dis[i]=max_length[i];
}
void copy_dis2()
{
	for(int i=1;i<=pointNumber;i++)
	point2_dis[i]=0;
	for(int i=1;i<=pointNumber;i++)
    point2_dis[i]=max_length[i];
}
int main()
{
    while(cin>>pointNumber)
    {
    init(pointNumber);
    int value,end_poiont=0;
    for(int i=2;i<=pointNumber;i++)
    {
        cin>>end_poiont>>value;
        addEdge(i,end_poiont,value);
        addEdge(end_poiont,i,value);
    }
    BFS(1);
    int point1=max_point;
    BFS(point1);
    copy_dis1();
    int point2=max_point;
    BFS(point2);
    copy_dis2();
    for(int i=1;i<=pointNumber;i++)
    {
        if(point1_dis[i]>point2_dis[i])
        printf("%d\n",point1_dis[i]);
        else
        printf("%d\n",point2_dis[i]);
    }
	/*for(int i=1;i<=pointNumber;i++)
	{
		int vis_flag=0;
		vis_flag=Map[i];
        cout<<i<<":";
		while(vis_flag!=-1)
		{
			cout<<Edges[vis_flag].end<<" "<<Edges[vis_flag].value<<"--";
            vis_flag=Edges[vis_flag].nxt;
		}
        cout<<endl;
	 }*/	
	}
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章