zoukankan      html  css  js  c++  java
  • bzoj1040题解

    【题意分析】

      给你一个带权基环树森林,求它的点集的无邻点子集的最大权值和。

    【解题思路】

      对于树的部分,做一遍拓扑排序+递推即可(f[i][j]表示第i个节点选取状态为j(0/1)可以得到的最大权值和)。时间复杂度O(n)。

      对于环的部分,做一遍DP。g[i][j]表示环上第i个节点选取状态为j时,编号从1到i的节点的最大子树权值和。转移方程:

    •g[i][0]=max(g[i-1][0],g[i-1][1])+f[i][0];

    •g[i][1]=g[i-1][0]+f[i][1];

      但因为这是个环,所以要枚举环上第一个元素取不取。若取,则答案为g[n][0],否则答案为max(g[n][0],g[n][1])。时间复杂度O(n)。

      总时间复杂度O(n)。

    【参考代码】

     1 #include <bits/stdc++.h>
     2 #define range(i,low,high) for(register int i=(low);i<(high);++i)
     3 #define dange(i,high,low) for(register int i=(high);i>(low);--i)
     4 #define __function__(type) __attribute__((optimize("-O2"))) inline type
     5 #define __procedure__      __attribute__((optimize("-O2"))) inline void
     6 using namespace std;
     7  
     8 static int n; bool vis[1000005]={0};
     9 int oue[1000005],ind[1000005],que[1000005],loop[1000005];
    10 long long v[1000005],f[1000005][2]={0},g[1000005][2];
    11  
    12 int main()
    13 {
    14     scanf("%d",&n);
    15     range(i,1,n+1) scanf("%lld%d",v+i,oue+i),++ind[oue[i]];
    16     int tail=0; long long ans=0;
    17     range(i,1,n+1) {f[i][1]=v[i]; if(!ind[i]) que[tail++]=i;}
    18     range(head,0,tail)
    19     {
    20         int fr=que[head],to=oue[fr]; vis[to]=1;
    21         f[to][0]+=max(f[fr][0],f[fr][1]),f[to][1]+=f[fr][0];
    22         if(!--ind[to]) que[tail++]=to;
    23     }
    24     range(i,1,n+1) if(ind[i]>0)
    25     {
    26         int cnt=1; --ind[loop[1]=i];
    27         for(int j=oue[i];j!=i;j=oue[j]) --ind[loop[++cnt]=j];
    28         g[1][0]=f[loop[1]][0],g[1][1]=0;
    29         range(j,2,cnt+1)
    30         {
    31             int k=loop[j];
    32             g[j][0]=max(g[j-1][0],g[j-1][1])+f[k][0];
    33             g[j][1]=g[j-1][0]+f[k][1];
    34         }
    35         long long tmp=max(g[cnt][0],g[cnt][1]);
    36         g[1][0]=0,g[1][1]=f[loop[1]][1];
    37         range(j,2,cnt+1)
    38         {
    39             int k=loop[j];
    40             g[j][0]=max(g[j-1][0],g[j-1][1])+f[k][0];
    41             g[j][1]=g[j-1][0]+f[k][1];
    42         }
    43         ans+=max(tmp,g[cnt][0]);
    44     }
    45     return printf("%lld
    ",ans),0;
    46 }
    View Code
  • 相关阅读:
    分布式事务的四种解决方案
    十大经典排序算法
    Vineyard 加入 CNCF Sandbox,将继续瞄准云原生大数据分析领域
    因你不同,2021 阿里云开发者大会重磅开启 @ 所有开发者!
    【深度】阿里巴巴万级规模 K8s 集群全局高可用体系之美
    业界率先支持 MCP-OVER-XDS 协议,Nacos 2.0.1 + 1.4.2 Release 正式发布
    被解救的代码
    KubeVela + KEDA:为应用带来“与生俱来”的弹性伸缩能力
    论好文章和烂文章
    Fluid 进入 CNCF Sandbox,加速大数据和 AI 应用拥抱云原生
  • 原文地址:https://www.cnblogs.com/spactim/p/6613246.html
Copyright © 2011-2022 走看看