【POJ2631】Roads in the North【樹的直徑】
阿新 • • 發佈:2018-12-15
題目大意:
題目連結:http://poj.org/problem?id=2631
求一棵樹的直徑。
思路:
樹的直徑模板題。
方法一:
樹形
求輸的直徑。
考慮以
為根節點,求出
表示從
到以
為根的子樹的任意節點的最大路徑和。那麼很明顯有
那麼再考慮求出
表示經過
的路徑中的最大路徑和。
那麼假設在該路徑上有兩點
和
,那麼就有
此時如果列舉
和
,時間複雜度就是
,十分不理想。
其實根本沒有必要列舉
和
。我們在求
時,就有
。那麼如果此時我們有列舉到了
的下一個子節點
,那麼此時我們就有了
那麼久可以直接更新
了!
其實可以根本不用
這個陣列,直接用
求直徑。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=10100;
int n,x,y,z,tot,ans,f[N],head[N];
struct edge
{
int to,dis,next;
}e[N*2];
void add(int from,int to,int dis)
{
e[++tot].to=to;
e[tot].dis=dis;
e[tot].next=head[from];
head[from]=tot;
}
void dp(int x,int fa)
{
for (int i=head[x];~i;i=e[i].next)
{
int y=e[i].to;
if (y==fa) continue;
dp(y,x);
ans=max(ans,f[x]+f[y]+e[i].dis); //求直徑
f[x]=max(f[x],f[y]+e[i].dis); //更新
}
}
int main()
{
memset(head,-1,sizeof(head));
while (scanf("%d%d%d",&x,&y,&z)==3)
{
add(x,y,z);
add(y,x,z);
}
dp(1,0);
printf("%d\n",ans);
return 0;
}
方法二:搜尋
我們先從
開始搜尋,可以求出一個與
之間路徑和最大的點
。那麼此時點p肯定是樹的其中一條直徑的起點,終點肯定是與p距離最遠的點q,樹的直徑就是p到q的路徑和
。
還是比較好理解的。在這就不過多贅述。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=10100;
int n,x,y,z,tot,p,head[N],f[N],maxn;
struct edge
{
int next,dis,to;
}e[N*2];
void add(int from,int to,int dis)
{
e[++tot].to=to;
e[tot].dis=dis;
e[tot].next=head[from];
head[from]=tot;
}
void dfs(int x,int fa,int s)
{
if (s>maxn) //從起點能到達最遠的點
{
maxn=s;
p=x;
}
for (int i=head[x];~i;i=e[i].next)
{
int y=e[i].to;
if (y==fa) continue;
dfs(y,x,s+e[i].dis);
}
return;
}
int main()
{
memset(head,-1,sizeof(head));
while (scanf("%d%d%d",&x,&y,&z)==3)
{
add(x,y,z);
add(y,x,z);
}
dfs(1,0,0);
maxn=0;
dfs(p,0,0);
printf("%d\n",maxn);
return 0;
}