LiberOJ -6210-tree -树形DP

  • 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;
    }
    

     

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值