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]的最大值和次大值
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 using namespace std; 5 const int N = 50005; 6 typedef long long LL; 7 LL inf = N * 100000ll; 8 9 inline LL max(LL a,LL b) {return a>b?a:b;} 10 inline LL max(LL a,LL b,LL c) {return (a>b?a:b)>c?(a>b?a:b):c;} 11 12 LL dp[N][2]; 13 vector<int> G[N]; 14 struct edge 15 { 16 int to,w; 17 }edges[2*N]; 18 19 void dfs(int u,int fa) 20 { 21 int sz=G[u].size(),v,w; 22 LL temp; 23 LL a=-inf,b=-inf,c=-inf; 24 for(int i=0;i<sz;i++) 25 { 26 v = edges[G[u][i]].to; 27 w = edges[G[u][i]].w; 28 if( v!=fa ) 29 { 30 dfs(v,u); 31 temp = max(dp[v][1]+w,w); 32 a = max(a,dp[v][0]); 33 if( temp > b ) 34 { 35 c = b; 36 b = temp; 37 } 38 else if( temp > c ) 39 c = temp; 40 } 41 } 42 dp[u][0]=max(a,b,b+c); 43 dp[u][1]=b; 44 } 45 46 int main() 47 { 48 int n,m; 49 int u,v,w; 50 51 while( ~scanf("%d%d",&n,&m) ) 52 { 53 for(int i=1;i<=n;i++) G[i].clear(); 54 for(int i=1;i<=m;i++) 55 { 56 scanf("%d%d%d",&u,&v,&w); 57 edges[i].to = v; 58 edges[i+m].to = u; 59 edges[i].w = edges[i+m].w = w; 60 G[u].push_back(i); 61 G[v].push_back(i+m); 62 } 63 dfs(1,0); 64 LL ans = -inf; 65 for(int i=1;i<=n;i++) 66 ans = max(ans,dp[i][0]); 67 printf("%lld ",ans); 68 //cout<<ans<<endl; 69 } 70 return 0; 71 }