牛客网 桂林电子科技大学第三届ACM程序设计竞赛 G.路径-带条件的树的直径变形-边权最大,边数偶数的树上的最长路径-树形dp

链接:https://ac.nowcoder.com/acm/contest/558/G

来源:牛客网

路径

小猫在研究树。
小猫在研究路径。
给定一棵N个点的树,每条边有边权,请你求出最长的一条路径,满足经过每个点最多一次,经过的边的条数为偶数,且边权和最大。
请输出这个最大的边权和。

输入描述:

第一行一个正整数N,表示节点个数。

接下来N−1行,第i行三个正整数

ui,vi,wi,表示第i条边连接点ui,vi,边权为wi。

输出描述:

一行一个正整数,表示最大的边权和。
示例1

输入

复制
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 }
原文地址:https://www.cnblogs.com/ZERO-/p/10733538.html