HDU2196-Computer-树形DP-求出树上距离每个节点最远的节点与之的距离

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题意:传送门

 原题目描述在最下面。

 一颗n个节点的树,每条边有权值。依次输出距离每个点最远节点与之的距离。

思路:

法一:

 首先距离每个节点最远的节点距离肯定是从u点向下搜索到的最远距离和向上搜索到的最远距离之一。
 你不可能暴力搜每个点。所以就要用dp数组记录一些贡献。

 第一次dfs求出每个节点的最远的子链距离dp[i][0]和次远子链距离dp[i][1]。同时记录最远子链的编号:fa[u] = v,v是u的儿子。 这步很简单。

 第二次dfs求出每个节点向上的最长距离dp[i][2]

if(fa[u] == v)dp[v][2] = max(dp[u][2], dp[u][1]) + w;
else dp[v][2] = max(dp[u][2], dp[u][0]) + w;

 每个节点v向上的最远距离肯定是由它父节点u传来的。
 如果v在u的最远子链上,那么dp[v][2]肯定是从dp[u][2]或dp[u][1]传来的,dp[v][2] = u->v + max(dp[u][2], dp[u][1])

 如果v步在u的最远子链上,那么dp[v][2]肯定是从dp[u][2]或dp[u][0]传来的,dp[v][2] = u->v + max(dp[u][2], dp[u][0])

 最后的答案就是max(dp[i][0], dp[i][2])

法二:

 记忆化搜索求出每条边可以到达的最远距离。

 暴力dfs输出每个答案。


AC代码:

法一:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cassert>
#define fi first
#define se second
#define pb push_back
using namespace std;
typedef long long LL;
const int N = 1e5 + 7;
const int INF = 0x3f3f3f3f;

// dp[i][0] : i向下最长距离
// dp[i][1] : i向下次长距离
// dp[i][2] : i向上距离

int n, m;
int dp[N][3], fa[N];
vector<pair<int,int> > mp[N];

void dfs1(int u,int Fa){
  int len = mp[u].size();
  for(int i = 0; i < len; ++i){
    int v = mp[u][i].fi;
    if(v == Fa)continue;
    dfs1(v, u);
    if(dp[v][0] + mp[u][i].se > dp[u][0]){
      fa[u] = v;
      dp[u][1] = dp[u][0];
      dp[u][0] = dp[v][0] + mp[u][i].se;
    }else if(dp[v][0] + mp[u][i].se > dp[u][1]){
      dp[u][1] = (dp[v][0] + mp[u][i].se);
    }
  }
}
void dfs2(int u, int Fa){
  int len = mp[u].size();
  for(int i = 0; i < len; ++i){
    int v = mp[u][i].fi;
    if(v == Fa)continue;
    if(fa[u] == v){
      dp[v][2] = max(dp[u][2], dp[u][1])+mp[u][i].se;
    }else{
      dp[v][2] = max(dp[u][2], dp[u][0])+mp[u][i].se;
    }
    dfs2(v, u);
  }
}
void init(){
  for(int i = 0; i <= n; ++i){
    mp[i].clear();
  }
  memset(dp, 0, sizeof(dp));
  memset(fa, 0, sizeof(fa));
}
int main(){
  while(~scanf("%d", &n)){
    init();
    for(int i = 2, u, v; i <= n; ++i){
      scanf("%d%d", &u, &v);
      int a = i, b = u;
      mp[a].pb(make_pair(b, v));mp[b].pb(make_pair(a, v));
    }
    dfs1(1,-1);
    /*for(int i = 1; i <= n; ++i){
      printf("%d %d %d\n", dp[i][0], dp[i][1], dp[i][2]);
    }
    printf("******\n");*/
    dfs2(1, -1);
    for(int i = 1; i <= n; ++i){
      printf("%d\n", max(dp[i][0], dp[i][2]));
    }
  }
  return 0;
}


法二:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010;
int n, tot, dp[N<<1], head[N];
struct lp{
  int u, v, w, nex;
  lp() {}
  lp(int u, int v, int w, int nex):u(u), v(v), w(w), nex(nex) {}
}cw[N<<1];
int dfs(int u, int nex){
  int ans = 0;
  for(int i=head[u]; ~i; i=cw[i].nex){
    int v = cw[i].v;
    if(v==nex) continue;
    if(!dp[i]) dp[i] = dfs(v, u)+cw[i].w;
    ans = max(ans , dp[i]);
  }
  return ans;
}
int main(){
  while(scanf("%d", &n)>0){
    memset(dp, 0, sizeof(dp));
    memset(head, -1, sizeof(head));
    tot = 0;
    for(int i = 2, v, w; i<=n; i++){
      scanf("%d%d", &v, &w);
      cw[tot] = lp(i, v, w, head[i]);
      head[i] = tot++;
      cw[tot] = lp(v, i, w, head[v]);
      head[v] = tot++;
    }
    for(int i=1; i<=n; i++){
      printf("%d\n", dfs(i,-1));
    }
  }
  return 0;
}


原题目描述:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/81124011