zoukankan      html  css  js  c++  java
  • BZOJ3887 [Usaco2015 Jan]Grass Cownoisseur[缩点]

    首先看得出缩点的套路。跑出DAG之后,考虑怎么用逆行条件。首先可以不用,这样只能待原地不动。用的话,考虑在DAG上向后走,必须得逆行到1号点缩点后所在点的前面,才能再走回去。

    于是统计从1号点缩点所在点到所有走到的点的最长距离,以及所有可以走到1号的点到1号的最长距离。然后,看在哪里逆行,可以暴力枚举每条边,然后把两边连接的点用预处理好的信息更新答案即可。这个可以使用正/反向跑图加记忆化。

    注意一点:这样统计是不会重复统计的,因为如果存在点可以从1号经过,逆行之后又经过这个点,回到1号点,那就有环了,不是DAG。

    忽略点($WA imes 1$):1号点也可能在环内,要以缩点之后的代表点来考虑。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define dbg(x) cerr << #x << " = " << x <<endl
     8 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
     9 using namespace std;
    10 typedef long long ll;
    11 typedef double db;
    12 typedef pair<int,int> pii;
    13 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    14 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    15 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    16 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    17 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    18 template<typename T>inline T read(T&x){
    19     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    20     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    21 }
    22 const int N=1e5+7,INF=0x3f3f3f3f;
    23 struct thxorz{int to,nxt;}G[N],dag[N],rdag[N];
    24 int Head[N],dhd[N],rhd[N],tot1,tot2,tot3,frm[N];
    25 int n,m;
    26 inline void Addedge(int x,int y){G[++tot1].to=y,G[tot1].nxt=Head[x],Head[x]=tot1;frm[tot1]=x;}
    27 inline void AddDAG(int x,int y){dag[++tot2].to=y,dag[tot2].nxt=dhd[x],dhd[x]=tot2;}
    28 inline void AddrDAG(int x,int y){rdag[++tot3].to=y,rdag[tot3].nxt=rhd[x],rhd[x]=tot3;}
    29 #define y G[j].to
    30 int dfn[N],low[N],cnt,instk[N],stk[N],Top,val[N],bel[N];
    31 void tarjan(int x){
    32     dfn[x]=low[x]=++cnt,stk[++Top]=x,instk[x]=1;
    33     for(register int j=Head[x];j;j=G[j].nxt){
    34         if(!dfn[y])tarjan(y),MIN(low[x],low[y]);
    35         else if(instk[y])MIN(low[x],dfn[y]);
    36     }
    37     if(dfn[x]==low[x]){int tmp;do instk[tmp=stk[Top--]]=0,bel[tmp]=x,++val[x];while(tmp^x);}
    38 }
    39 #undef y
    40 int ans1[N],ans2[N],vis[N],ans;
    41 #define y rdag[j].to
    42 int dp1(int x){//dbg2(x,val[x]);
    43     if(vis[x])return ans1[x];
    44     vis[x]=1;
    45     for(register int j=rhd[x];j;j=rdag[j].nxt)MAX(ans1[x],dp1(y)+val[x]);
    46     return ans1[x];
    47 }
    48 #undef y
    49 #define y dag[j].to
    50 int dp2(int x){
    51     if(vis[x])return ans2[x];
    52     vis[x]=1;
    53     for(register int j=dhd[x];j;j=dag[j].nxt)MAX(ans2[x],dp2(y)+val[x]);
    54     return ans2[x];
    55 }
    56 #undef y
    57 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    58     read(n),read(m);
    59     for(register int i=1,x,y;i<=m;++i)read(x),read(y),Addedge(x,y);
    60     for(register int i=1;i<=n;++i)if(!dfn[i])tarjan(i);
    61     for(register int t=1,u,v;t<=tot1;++t){
    62         u=frm[t],v=G[t].to;
    63         if(bel[u]^bel[v])AddDAG(bel[u],bel[v]),AddrDAG(bel[v],bel[u]);//CAUTION!LOOP!
    64     }
    65     fill(ans1+1,ans1+n+1,-INF),fill(ans2+1,ans2+n+1,-INF);ans1[bel[1]]=ans2[bel[1]]=0;
    66     for(register int i=1;i<=n;++i)if(val[i])dp1(i);
    67     memset(vis,0,sizeof vis);ans=val[bel[1]];
    68     for(register int i=1;i<=n;++i)if(val[i])dp2(i);
    69     for(register int t=1,u,v;t<=tot2;++t){
    70         u=rdag[t].to,v=dag[t].to;
    71         MAX(ans,ans1[v]+ans2[u]+val[bel[1]]);
    72     }
    73     printf("%d
    ",ans);
    74     return 0;
    75 }
    View Code

    问题总结:缩点记忆化dp要常检查两样:初始化及边界、缩点是否影响了什么(会不会出错)。

  • 相关阅读:
    eclipsesvn
    js邮箱和正则表达式
    jsreplace
    JQuery与Json转换
    thinkPHP时间戳格式化
    JS绝对定位到右下角
    chrome快捷键
    js配置示例
    JQuery class选择器
    JS调试技巧
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11712090.html
Copyright © 2011-2022 走看看