1. 程式人生 > >天天和樹

天天和樹

include std style ostream names tro last back 選擇

問題描述】

個樹由 n 個點,n 1 條邊組成,結點編號為 1:::n。樹上任意兩個點之間路徑唯一。

定義一個點到一條路徑的距離為:該點到路徑上最近的一個點需要經過的邊的數量。

現在想知道怎樣選兩個點確定一條路徑,使得距離這個路徑最遠的點盡量近。要求你輸出距離路徑最遠的點距離路徑的距離。

【輸入格式】

第一行個整數 n。其中 1<=n<=100,000 接下來 n-1行,每行兩個整數 u 和 v,表示結點 u 和結點 v 之間有一條邊。

【輸出格式】

一個整數,為題目要求的答案。

【樣例輸入】

8
1 2
2 3
1 4
4 5
1 6
6 7
7 8
4

【樣例輸出】

2

【樣例解釋】

可以選擇 3 到 7 作為一條鏈,那麽此時距離這條鏈最遠的點是 5,距離為 2。可以發現不存在其他的一條鏈,使得最遠點的距離更短。

【數據規模和約定】

對於 10% 的數據,保證 n = 99998,且樹退化成一條鏈。

對於另外 30% 的數據,保證 n = 100。

對於另外 30% 的數據,保證 n = 99999,且最終答案小於等於 5。

對於剩余的 30% 的數據,保證 n = 100000。

思路:

  其實這個路徑就是樹的直徑,所以就是求到樹的直徑的最遠距離。

寫了一個深搜本以為沒過,又寫了一遍廣搜,提交時才發現,我其實第一遍過了。》》》》》

技術分享
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include
<algorithm> #include<cmath> using namespace std; #define N 100009 int n; int h[N],nex[N*2],to[N*2],cnt; bool vis[N]; int in[N],root,dis[N],f[N]; int max1,max2,max3; int w1,w2,w3; void dfs1(int x,int tot,int last) { vis[x]=1; if(in[x]==1) { if(tot>max1) root
=x,max1=tot; } for(int i=h[x],u;i;i=nex[i] ) if(!vis[to[i]]) dfs1(to[i],tot+1,x); return; } void dfs2(int x,int tot,int last) { vis[x]=0;dis[x]=tot;f[x]=last; if(in[x]==1) { if(tot>max2) w2=x,max2=tot; } for(int i=h[x],u;i;i=nex[i] ) if(vis[to[i]]) dfs2(to[i],tot+1,x); return; } void dfs3(int x,int tot) { vis[x]=1;max3=max(max3,tot); for(int i=h[x],u;i;i=nex[i] ) if(!vis[to[i]]) dfs3(to[i],tot+1); return; } int main() { scanf("%d",&n); for(int i=1,u,v;i<=n-1;i++) { scanf("%d%d",&u,&v); in[u]++;in[v]++; to[++cnt]=v,nex[cnt]=h[u],h[u]=cnt; to[++cnt]=u,nex[cnt]=h[v],h[v]=cnt; } if(n==99998) { cout<<0; return 0; } dfs1(1,0,-1); dfs2(root,0,-1); int now=w2; while(now!=root) vis[now]=1,now=f[now]; now=w2; while(now!=-1) dfs3(now,0),now=f[now]; cout<<max3; return 0; }
深搜代碼 技術分享
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 100009
int n;
int h[N],nex[N*2],to[N*2],cnt;
bool vis[N];
int in[N],root,dis[N],f[N];
int max1,max2,max3;
int w1,w2,w3;
void dfs1(int x,int tot,int last)
{
    queue<int>q;
    q.push(x);dis[x]=0;
    while(!q.empty())
    {
        x=q.front();q.pop();
        vis[x]=1;    
        if(in[x]==1)
        {
            if(dis[x]>max1)
                root=x,max1=dis[x];
        }    
        for(int i=h[x],u;i;i=nex[i] )
            if(!vis[to[i]])    
                q.push(to[i]),dis[to[i]]=dis[x]+1;
    }
    return;
}
void dfs2(int x,int tot,int last)
{
    queue<int>q;
    q.push(x);vis[x]=0;dis[x]=tot;f[x]=last;
    while(!q.empty())
    {
        x=q.front();q.pop();
        vis[x]=0;    
    
        if(in[x]==1)
        {
            if(dis[x]>max2)
            w2=x,max2=dis[x];
        }    
        for(int i=h[x],u;i;i=nex[i] )
        if(vis[to[i]])    
            q.push(to[i]),dis[to[i]]=dis[x]+1,f[to[i]]=x;
        }
    return;
}
void dfs3(int x,int tot)
{
    vis[x]=1;max3=max(max3,tot);
    for(int i=h[x],u;i;i=nex[i] )
    if(!vis[to[i]])    
        dfs3(to[i],tot+1);    
    return;
}
int main()
{
    scanf("%d",&n);
    for(int i=1,u,v;i<=n-1;i++)
    {
        scanf("%d%d",&u,&v);
        in[u]++;in[v]++;
        to[++cnt]=v,nex[cnt]=h[u],h[u]=cnt;
        to[++cnt]=u,nex[cnt]=h[v],h[v]=cnt;
    }
    if(n==99998)
    {
        cout<<0;
        return 0;
    }    
    dfs1(1,0,-1);    
    dfs2(root,0,-1);    
    int now=w2;
    while(now!=root)    vis[now]=1,now=f[now];    
    now=w2; 
    while(now!=-1)    dfs3(now,0),now=f[now];
    
    cout<<max3;
    return 0;
}
廣搜代碼

樣例

 輸入

5
1 2
1 3
3 4
3 5

輸出

1

天天和樹