• 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
  • 相关阅读:
    Java笔记6之三目运算符
    java笔记5之逻辑运算符以及&&与&的区别
    SAP CRM OData模型里的addressable为true的含义
    SAP CRM OData multiple origin Composition的测试
    重构老系统遗留代码的一些方法学习笔记
    SAP CRM系统里的附件存储逻辑
    如何用Postman创建SAP CRM的Opportunity业务数据
    另一种使用SAP SAT事务码对通过浏览器启动的应用的性能测量和分析方式
    SAP Hybris Commerce,CRM和C4C的登录语言选择
    SAP Hybris Commerce的页面路由实现
  • 原文地址:https://www.cnblogs.com/spactim/p/6613246.html
Copyright © 2020-2023  润新知