中南大学oj 1317 Find the max Link 边权可以为负的树上最长路 树形dp 不能两遍dfs

时间:2023-03-09 09:37:08
中南大学oj 1317 Find the max Link 边权可以为负的树上最长路 树形dp 不能两遍dfs

http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1317
经典问题:
树上最长路,边权可以为负值的,树形dp,不能用两边dfs。
反例:
5 4
1 2 2
2 3 1
2 4 -100
4 5 10
写树形dp的时候,WA了好多次,错误在于:
记录单链的时候,一个节点的最长单链不一定等于:边权+孩子的最长单链
还可以不选孩子,只要边权就行!!!!!!
如果边权非负的话,就是 边权+孩子的最长单链 了。

思路:

  dp[u][0],记录的是以u为根结点的子树中的最长路

  dp[u][1],记录的是以u为起点的向下的一条最长链

转移时:

  a记录的是max{ dp[sons][0] }

  b和c记录的分别是dp[sons][1]的最大值和次大值

 #include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
const int N = ;
typedef long long LL;
LL inf = N * 100000ll; inline LL max(LL a,LL b) {return a>b?a:b;}
inline LL max(LL a,LL b,LL c) {return (a>b?a:b)>c?(a>b?a:b):c;} LL dp[N][];
vector<int> G[N];
struct edge
{
int to,w;
}edges[*N]; void dfs(int u,int fa)
{
int sz=G[u].size(),v,w;
LL temp;
LL a=-inf,b=-inf,c=-inf;
for(int i=;i<sz;i++)
{
v = edges[G[u][i]].to;
w = edges[G[u][i]].w;
if( v!=fa )
{
dfs(v,u);
temp = max(dp[v][]+w,w);
a = max(a,dp[v][]);
if( temp > b )
{
c = b;
b = temp;
}
else if( temp > c )
c = temp;
}
}
dp[u][]=max(a,b,b+c);
dp[u][]=b;
} int main()
{
int n,m;
int u,v,w; while( ~scanf("%d%d",&n,&m) )
{
for(int i=;i<=n;i++) G[i].clear();
for(int i=;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
edges[i].to = v;
edges[i+m].to = u;
edges[i].w = edges[i+m].w = w;
G[u].push_back(i);
G[v].push_back(i+m);
}
dfs(,);
LL ans = -inf;
for(int i=;i<=n;i++)
ans = max(ans,dp[i][]);
printf("%lld\n",ans);
//cout<<ans<<endl;
}
return ;
}