(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
题意:传送门
原题目描述在最下面。
一颗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;
}