樹:解決最大網線長度問題。c++

網線長度

實驗室裏原先有一臺電腦(編號爲1),最近又爲實驗室購置了N-1臺電腦,編號爲2到N。每臺電腦都用網線連接到一臺先前安裝的電腦上。我們希望知道第i臺電腦到其他電腦的最大網線長度。
在這裏插入圖片描述

提示: 樣例輸入對應這個圖,從這個圖中你可以看出,距離1號電腦最遠的電腦是4號電腦,他們之間的距離是3。 4號電腦與5號電腦都是距離2號電腦最遠的點,故其答案是2。5號電腦距離3號電腦最遠,故對於3號電腦來說它的答案是3。同樣的我們可以計算出4號電腦和5號電腦的答案是4.

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

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

sample input:
5
1 1
2 1
3 1
1 1

sample output:
3
2
3
4
4

思路

  • 題目說了這麼多,其實就是構建一棵樹,然後尋找離每個節點最遠的結點
  • 所以起初我使用樹形DP的做法來解決這個問題,把無根樹化爲有根樹來處理

在這裏插入圖片描述

  • 比如對於上面這棵樹,要求點4的最長距離,可以將樹tree1分解成以節點4爲根節點的tree2和以節點4的父節點爲根節點的樹tree1-tree2;這樣的話,對於整棵樹來說,tree2中距離節點2最遠的距離記作l1,tree1-tree2中最遠的距離記作l2,那麼最終的答案就是max(l1,l2+1).
  • 利用一個二維數組來記錄。f[i][0]表示頂點爲i的子樹距離頂點i的最長距離;f[i][1]表示i的父節點的子樹-i子樹的最長距離+1(i與i的父節點距離)
  • 所有的f[i][0]都做一次dfs求每一個節點到葉子節點的最長距離,然後從父節點遞推到子節點計算所有的f[i][1]
  • 這種經典樹形DP的實現代碼如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
struct edge
{
	int v,w,next;
}edge[10111];
int head[10111];
int n;
void add(int u,int v,int w)
{
	edge[n].v=v;
	edge[n].w=w;
	edge[n].next=head[u];
	head[u]=n++;
}
long long path[3][10011];
int visit[10011];
void dfs(int u,int far)
{
	long long mx0=0,mx1=0;
	for(int i=head[u];i!=-1;i=edge[i].next)
	{
	int v=edge[i].v;
	if(v==far)	continue;
	dfs(v,u);
	if(mx0<=path[0][v]+edge[i].w)	
	{
	mx1=mx0;
	mx0=path[0][v]+edge[i].w;
	visit[u]=v;
	}
	else if(mx1<path[0][v]+edge[i].w)	mx1=path[0][v]+edge[i].w;
	else if(mx1<path[1][v]+edge[i].w)	mx1=path[1][v]+edge[i].w;
	}
	path[0][u]=mx0;
	path[1][u]=mx1;
}
void dfss(int u,int far)
{
	for(int i=head[u];i!=-1;i=edge[i].next)
	{
		int v=edge[i].v;
		if(v==far)	continue;
		if(visit[u]==v)	path[2][v]=max(path[1][u]+edge[i].w,path[2][u]+edge[i].w);
		else path[2][v]=max(path[0][u]+edge[i].w,path[2][u]+edge[i].w);
		dfss(v,u);
	}
}
int main()
{
	int a,b,c;
	while (~scanf("%d",&c))
	{
		n=0;
		memset(head,-1,sizeof(head));
		for(int i=2;i<=c;i++)
		{
		scanf("%d%d",&a,&b); 
		add(i,a,b);
		add(a,i,b);
		}
		memset(path,0,sizeof(path));
		dfs(1,1);
		dfss(1,1);
		for(int i=1;i<=c;i++)
		cout<<max(path[0][i],path[2][i])<<endl;
	}
	return 0;
}
  • 但是這樣寫出現了TLE的問題,可能是測試數據卡的比較嚴,所以採用另一種思路,對於樹中任意頂點進行一遍bfs,找到一個距離它最遠的頂點作爲端點1(肯定是一個葉子節點),然後再從端點進行bfs,找到距離最遠的點,肯定是一個葉子節點,我們認爲他是端點2
  • 這樣的話以這兩個端點爲起點對這棵樹中所有的點都進行bfs,記錄下距離最終的結果就是兩個端點到這個點的距離的較大值
  • 我們將樹中最遠的兩個葉子節點之間的距離成爲樹的直徑,這兩個點被稱爲端點;整棵樹中任意兩個節點之間的距離都小於等於樹的直徑
#include<iostream>
#include<algorithm>
#include<queue>
#include<string.h>
using namespace std;
const int N=500001;
struct edge
{
    int u,v;
	int w;
	int next;
}e[N];
int a[N],visit[N],dis[N];
int tot;
int p1,p2;
int ans[2][N];//0,1
void add(int u,int v,int w)
{
	tot++;
    e[tot].u=u;
    e[tot].v=v;
    e[tot].w=w;
    e[tot].next=a[u];
    a[u]=tot;
}
void bfs(int node,int flag)
{
    memset(visit,0,sizeof(visit));
    memset(dis,0,sizeof(dis));
    int length=0;
    queue<int> q;
    q.push(node);
    visit[node]=true;
    while(!q.empty())
    {
        int temp=q.front();
		q.pop();
        for(int i=a[temp];i!=-1;i=e[i].next)
        {
            int nex=e[i].v;
            if(!visit[nex])
            {
                dis[nex]=dis[temp]+e[i].w;
                if(dis[nex]>length)
                {
                    length=dis[nex];
                    if(flag==true)
                    p1=nex;
                    else p2=nex;
                }
                visit[nex]=1;
                q.push(nex);
            }
        }
    }
}
void bfss(int node,int flag)
{
    memset(visit,0,sizeof(visit));
    queue<int> q;
    q.push(node);
    visit[node]=true;
    while(!q.empty())
    {
        int temp=q.front();
		q.pop();
        for(int i=a[temp];i!=-1;i=e[i].next)
        {
            int nex=e[i].v;
            if(!visit[nex])
            {
                ans[flag][nex]=ans[flag][temp]+e[i].w;     
                visit[nex]=true;
                q.push(nex);
            }
        }
    }
}
int main()
{
	int n;
    while(scanf("%d",&n)!=EOF)
{ 
    memset(ans,0,sizeof(ans));
    tot=0;
	p1=0;p2=0;
    int u,v,w;
    for(int i=1;i<=n;i++)   
	a[i]=-1;
    for(int i=2;i<=n;i++)
    {
        scanf("%d%d",&v,&w);
        add(i,v,w);
        add(v,i,w);
    }
	bfs(1,1);
    bfs(p1,2);
    bfss(p1,0);
	bfss(p2,1);
    for(int i=1;i<=n;i++)
        printf("%d\n",max(ans[0][i],ans[1][i]));
}
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章