• 【HNOI2009】无归岛


    题面

    https://www.luogu.org/problemnew/show/P4410

    题意:求仙人掌上最大独立集。

    1. $orzyyb$ $tarjan$中顺便$dp$的思路是在是太妙了。
    2. 同时用两个数组处理问题,减少思维复杂度(我jo的我写的代码总有一种暴力美学)。
    3. $g[x][0/1]$ 表示$x$及$x$的子树中,如果x选,最大独立集是多少。
    4. $f[x][0/1][0/1]$ 有意义当且仅当$x$在环上,并且不为环的头。 设$x$为环的头,$t$为环的尾,$f[y][0/1][0/1]$ 表示$y$ 选或不选,$t$选或不选,$y$及$y$的子树里的最大独立集是多少。
    5. 然后转移就可以了,注意要在$y$中扣除先前转移$t$的影响。
    // luogu-judger-enable-o2
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<stack>
    #include<vector>
    #define INF 1000000007
    #define ri register int
    #define N 100500
    using namespace std;
    
    int n,tn,m;
    int cir[N];
    int a[N];
    int ans;
    
    inline int read() {
      int ret=0,f=0; char ch=getchar();
      while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
      while (ch>='0'&&ch<='9') ret*=10,ret+=ch-'0',ch=getchar();
      return f?-ret:ret;
    }
    
    struct graph {
      vector<int> to[N];
      int dfn[N],low[N],cnt;
      stack<int> s;
      int f[N][2][2],g[N][2];
        // state:t  state:x
      void add_edge(int a,int b) {
        to[a].push_back(b);
        to[b].push_back(a);
      }
      void tarjan(int x) {
        dfn[x]=low[x]=++cnt; s.push(x);
        g[x][1]=a[x];
        g[x][0]=0;
        for (ri i=0;i<to[x].size();i++) {
          int y=to[x][i];
          if (dfn[y]) low[x]=min(low[x],dfn[y]);
          else {
            tarjan(y);
            low[x]=min(low[x],low[y]);
            if (low[y]>=dfn[x]) {
              int t=s.top();
                        
              if (t==y) {
                 g[x][1]+=max(g[y][0],0);
                 g[x][0]+=max(max(g[y][1],g[y][0]),0);
                 continue;
              }
                        
              int pret=t;
              s.pop();
                        
              f[t][1][1]=g[t][1];
              f[t][0][0]=g[t][0];
              f[t][1][0]=f[t][0][1]=-INF;
                        
              do {
                t=s.top(); s.pop();
                f[t][1][0]=g[t][1]-max(g[pret][0],0)+max(f[pret][0][0],0);
                f[t][0][0]=g[t][0]-max(max(g[pret][0],g[pret][1]),0)+max(max(f[pret][0][0],f[pret][1][0]),0);
                f[t][1][1]=g[t][1]-max(g[pret][0],0)+max(f[pret][0][1],0);
                f[t][0][1]=g[t][0]-max(max(g[pret][0],g[pret][1]),0)+max(max(f[pret][0][1],f[pret][1][1]),0);
                pret=t;
              }
              while (t!=y);
              g[x][1]+=max(f[y][0][0],0);
              g[x][0]+=max(max(max(f[y][0][0],f[y][0][1]),max(f[y][1][0],f[y][1][1])),0);
            }
            else {
              g[x][1]+=max(g[y][0],0);
              g[x][0]+=max(max(g[y][1],g[y][0]),0);
            }
          }
        }
      }
    } G;
    
    int main() {
      tn=n=read(); m=read();
      for (ri i=1;i<=m;i++) {
        int u=read(),v=read();
        G.add_edge(u,v);
      }
      for (ri i=1;i<=n;i++) a[i]=read();
      G.cnt=0;
      G.tarjan(1);
      int ans=0;
      for (ri i=1;i<=n;i++) ans=max(ans,max(G.g[i][0],G.g[i][1]));
      printf("%d
    ",ans);
    }
  • 相关阅读:
    java
    图解MotionEvent中getRawX、getRawY与getX、getY以及View中的getScrollX、getScrollY
    ListView分栏--制作分栏音乐列表
    Android中Touch事件的传递机制
    Android进程间通信之使用AIDL
    Android进程间通信之使用Messenger
    Android Mms之短信接收流程--从Framework到App
    Android组件的使用:ListView、GridView
    Android组件的使用:AutoCompleteTextView、Spinner
    Android组件的使用:DatePicker,TimePicker
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11080541.html
Copyright © 2020-2023  润新知