Road is in north求树的直径裸题

题目:poj2631.

题目大意:给出一棵树带边权,找出两个点之间路径边权之和最长的长度.

这道题就是经典的树的直径的问题.

这种问题一般有两种方案做到O(n),一种是树形dp,一种是两遍bfs.

树形dp是用f[i]表示以它为根节点的子树中,离它最远的节点到它的距离.

我们发现,那么以每个节点k为根的子树中必须要有这个节点k的最长链可以表示为d[x]+d[y]+dis[x][k]+dis[y][k],其中dis[i][j]表示i到j这条边的边权,x和y都是k的子节点,且x在k的儿子中d[x]最大,y在k的儿子中d[y]次大.

所以我们可以轻松写出代码:

#include<bits/stdc++.h>      //头文件自己去改吧,我改过了交上去是对的
  using namespace std;
const int N=10000;
struct tree{
  int y,next,v;
}e[N*2];
bool use[N+1];
int top,m,ans,d[N+1],lin[N+1];
void ins(int X,int Y,int V){
  e[++top].y=Y;e[top].v=V;
  e[top].next=lin[X];
  lin[X]=top;
}
inline void into(){
  int x,y,v;
  while (~scanf("%d%d%d",&x,&y,&v))
    ++m,ins(x,y,v),ins(y,x,v);
}
void dfs(int k){      //树形dp
  use[k]=1;
  for (int i=lin[k];i;i=e[i].next)
    if (!use[e[i].y]){
      dfs(e[i].y);
      ans=max(ans,d[k]+d[e[i].y]+e[i].v);
      d[k]=max(d[k],d[e[i].y]+e[i].v);
    }
}
inline void work(){
  dfs(1);
}
inline void outo(){
  printf("%d\n",ans);
}
int main(){
  into();
  work();
  outo();
  return 0;
}

还有一种做法是两次bfs求树的直径.

这种做法先从任意一个节点(比如说节点1)出发找到距离它最远的节点,将这个节点k作为树的直径的出发点,再次bfs,找到距离节点k最远的节点,作为树的直径的截止点.

然后这两个点之间的距离就是树的直径长度.

证明就略过了.

这种做法比树形dp更容易找到路径,而且效率也是O(n)的.

关于常数,这种做法虽然需要跑两遍,但是没有用到递归,所以常数也较小.

那么代码如下:

//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstring> 
  using namespace std;
const int N=10000;
struct tree{
  int y,next,v;
}e[N*2];
bool use[N+1];
int top,m,ans,d[N+1],lin[N+1],dis[N+1],h,t,q[N+1];
void ins(int X,int Y,int V){
  e[++top].y=Y;e[top].v=V;
  e[top].next=lin[X];
  lin[X]=top;
}
inline void into(){
  int x,y,v;
  while (~scanf("%d%d%d",&x,&y,&v))
    ++m,ins(x,y,v),ins(y,x,v);
}
int bfs(int start){      //bfs返回距离start最远的点,并计算一个dis数组
  int nod=start;
  memset(use,0,sizeof(use));
  h=0;q[t=1]=start;dis[start]=0;use[start]=1;
  while (h^t)
    for (int i=lin[q[++h]];i;i=e[i].next)
      if (!use[e[i].y]) {
        dis[q[++t]=e[i].y]=dis[q[h]]+e[i].v;
        use[e[i].y]=1;
        if (dis[e[i].y]>dis[nod]) nod=e[i].y;
      }
  return nod;
}
inline void work(){
}
inline void outo(){
  printf("%d\n",dis[bfs(bfs(1))]);
}
int main(){
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/80638521
今日推荐