链接:https://ac.nowcoder.com/acm/contest/558/G
来源:牛客网
路径
输入描述:
第一行一个正整数N,表示节点个数。
接下来N−1行,第i行三个正整数
ui,vi,wi,表示第i条边连接点ui,vi,边权为wi。
输出描述:
一行一个正整数,表示最大的边权和。
输入
复制5 1 2 5 1 3 5 2 4 5 2 5 1
输出
复制10
备注:
1≤N≤10
5
,1≤w
i
≤10
9
,保证输入数据形成一棵树。
一开始智障了,以为直接搜索跑个树的直径然后删边就可以。最后发现想的太简单了,只能用树dp写。
二维dp,0表示偶数条边情况下,1表示奇数。
因为按边算,叶子节点为0,赋值0,1的赋值-inf,往上,到父节点,父节点的状态为,父亲的偶数情况为儿子节点的奇数情况+边权,奇数情况也一样。
dp[u][0]表示从叶子节点到当前节点u,偶数条边的最大值,奇数同理。到根节点的时候,偶数情况有两种:1.两个奇数条边的子树的链的和。2.两个偶数条边的子树的链的和。
代码:
1 //G-树上的dp 2 #include<bits/stdc++.h> 3 using namespace std; 4 typedef long long ll; 5 const int maxn=1e5+10; 6 const ll inf=1e18+10; 7 8 ll dp[maxn+10][2]; 9 10 struct node{ 11 int to; 12 ll val; 13 }; 14 15 int n; 16 ll ans=-inf; 17 vector<node> G[maxn<<1]; 18 bool vis[maxn]; 19 20 void dfs(int u) 21 { 22 vis[u]=true; 23 for(int i=0;i<G[u].size();i++){ 24 int v=G[u][i].to; 25 ll w=G[u][i].val; 26 if(vis[v]) continue; 27 dfs(v); 28 //两个端点相连的 奇数+奇数 或者偶数+偶数的 29 ans=max(ans,dp[u][1]+dp[v][0]+w); 30 ans=max(ans,dp[u][0]+dp[v][1]+w); 31 dp[u][1]=max(dp[u][1],dp[v][0]+w); 32 dp[u][0]=max(dp[u][0],dp[v][1]+w); 33 } 34 } 35 36 int main() 37 { 38 scanf("%d",&n); 39 for(int i=1;i<n;i++){ 40 int u,v;ll w; 41 scanf("%d%d%lld",&u,&v,&w); 42 G[u].push_back({v,w}); 43 G[v].push_back({u,w}); 44 } 45 memset(vis,false,sizeof(vis)); 46 for(int i=1;i<=n;i++){ 47 dp[i][0]=0; 48 dp[i][1]=-inf; 49 } 50 dfs(1); 51 cout<<ans<<endl; 52 }