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
  • 相关阅读:
    关于《哈利波特》书的购买方案
    你的灯亮着吗读后感三
    jmeter做接口测试
    jmeter的分布式部署
    JMeter的定时器
    我的功能测试用例是怎么写
    常见的功能测试检查点
    测试用例概论
    敏捷开发与迭代开发
    软件测试模型
  • 原文地址:https://www.cnblogs.com/spactim/p/6613246.html
Copyright © 2011-2022 走看看