链接:https://ac.nowcoder.com/acm/contest/558/G
来源:牛客网
路径
小猫在研究树。
小猫在研究路径。
给定一棵N个点的树,每条边有边权,请你求出最长的一条路径,满足经过每个点最多一次,经过的边的条数为偶数,且边权和最大。
请输出这个最大的边权和。
输入描述:
第一行一个正整数N,表示节点个数。
接下来N−1行,第i行三个正整数
ui,vi,wi,表示第i条边连接点ui,vi,边权为wi。
输出描述:
一行一个正整数,表示最大的边权和。
备注:
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 }