- https://loj.ac/problem/6210
- 题意 :按照定义的路径计算权值方式找一条最小的权值路径。
- 思路 :设定dp[ i ] [ 0 / 1 ] 以1为根的情况下,以 i 节点下子树走分别全1和走一次2和剩余全走1 的最长链
- 每遍历一次子树,统计一次答案,DP过程中 ans1,统计 路径全为1的最大值。
- ans2统计路径走 一段1中间一个2再走一段1的最长距离,三个最值更新方程,
- ans1 = max(ans1,dp[to][0] + dp[u][0]); DP[u][0]记录的是除了 to 这条路径 从u出发的最长路 。
- dp[to][0]则是记录的以to 为根全走1的最长路 , 这样 ans1最终记录的是 以每个点为根 所能造出的全部为1的最长路
- ans2 = max(ans2,dp[u][0] + dp[to][1]);
- ans2 = max(ans2,dp[u][1] + dp[to][0]);
- 同理 ans2在记录以每个点为根所能造成的(一段 1 一个 2 一段 1 )这样路径的最大值。
- 一定是 ans1,ans2先统计 维护最值,在进行跟新这个点为根的 两种 路径的最大值。
-
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f #define maxn 523456 int n,x[maxn],a,b,ans; int dp[maxn][2],ans1,ans2; vector<int>gra[maxn]; void dfs(int u,int p) { if(x[u]==1)dp[u][0]=1; else if(x[u]==2)dp[u][1]=1; for(int i=0; i<gra[u].size(); i++) { int v=gra[u][i]; if(v==p)continue; dfs(v,u); ans1=max(ans1,dp[u][0]+dp[v][0]); ans2=max(ans2,dp[u][0]+dp[v][1]); ans2=max(ans2,dp[u][1]+dp[v][0]); if(x[u]>2)continue; else if(x[u]==1) { dp[u][0]=max(dp[u][0],dp[v][0]+1); dp[u][1]=max(dp[u][1],dp[v][1]+1); } else dp[u][1]=max(dp[u][1],dp[v][0]+1); } } int main() { scanf("%d",&n); for(int i=1; i<n; i++) { scanf("%d%d",&a,&b); gra[a].push_back(b); gra[b].push_back(a); } ans=inf; for(int i=1; i<=n; i++) { scanf("%d",&x[i]); ans=min(ans,x[i]); } if(ans>1) printf("%d/1\n",ans); else { dfs(1,0); if(ans1*2>ans2)printf("1/%d\n",ans1); else if(ans2%2==0)printf("1/%d\n",ans2/2); else printf("2/%d\n",ans2); } return 0; }
LiberOJ -6210-tree -树形DP
最新推荐文章于 2021-07-27 18:43:02 发布