[USACO15JAN]草鉴定Grass Cownoisseur

【题目描述】:
[USACO15JAN]草鉴定Grass Cownoisseur

【思路】:
首先我们先思考贝茜不走那条反边,那么对于任意强连通分量\(E\)易知:

  • \(\forall u,v \in E\)\(\exists u \to v \ and \ v \to u\)

\(\because\)贝茜每次经过一个草场时只会吃一次草,\(\therefore\)可以进行缩点,缩点后得到一个\(DAG\),统计每一个强连通分量的\(size\)值,表示此强连通分量中有多少个点,然后在\(DAG\)上跑\(DP\)即可。

但是这道题贝茜玩蛇皮,她还可以逆行一次。

所以我们应该换一个思路,缩完点后,考虑到逆行的情况,我们可以把图正反都建一次,设1号点所在的强连通分量为\(E\),求出\(dis1[]\)\(dis2[]\),分别表示以\(E\)为起点和以\(E\)为中点的最长路,然后枚举每一个\(i\),那么答案就是:

  • \(max \{ dis1[i] +dis2[v] - size[E]\}\)

这就相当于走了那条反边。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;

int n,m;

const int MAXN = 100005;

struct edge{
    int u,v,nxt;
}e[MAXN];int head[MAXN];int cnt = 0;int dfn[MAXN];int low[MAXN];int id = 0;int s[MAXN];int tot = 0;int Bcnt = 0;
int x[MAXN];int y[MAXN];bool vis[MAXN];int size[MAXN];int b[MAXN];bool back[MAXN];int dis1[MAXN];int dis2[MAXN];int ans = -inf;

inline void add(int u,int v){
    e[++cnt].u = u;e[cnt].v = v;e[cnt].nxt = head[u];head[u] = cnt;
}

inline void tarjan(int u){
    low[u] = dfn[u] = ++id;
    s[++tot]=u;vis[u] = 1;
    for(int i=head[u];i;i=e[i].nxt){
        int v = e[i].v;
        if(!dfn[v]){
            tarjan(v);
            low[u] = min(low[u] , low[v]);
        }
        else if(vis[v]) low[u] = min(low[u] , dfn[v]);
    }
    
    if(dfn[u] == low[u]){
        int j=0;Bcnt++;
        while(j ^ u){
            j = s[tot--];
            vis[j] = 0;
            b[j] = Bcnt;
            size[Bcnt]++;
        }
    }
}

inline bool cmp(int a,int b){
    return a > b;
}

queue<int>q;
inline void dp(int *dis){
    memset(dis,0,sizeof dis);
    memset(vis,0,sizeof vis);
    dis[b[1]] = size[b[1]];
    q.push(b[1]);
    
    while(!q.empty()){
        int u = q.front();q.pop();vis[u] = 0;
        for(int i=head[u];i;i=e[i].nxt){
            int v = e[i].v;
            if(dis[v] < dis[u] + size[v]){
                dis[v] = dis[u] + size[v];
                if(!vis[v]){
                    q.push(v);
                    vis[v] = 1;
                }
            }
        }
    }
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i){
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);
        x[i] = u;y[i] = v;
    }
    for(int i=1;i<=n;++i){
        if(!dfn[i]){
            tarjan(i);
        }
    }
    
    memset(head,0,sizeof head);cnt = 0;
    for(int i=1;i<=m;++i){
        if(b[x[i]] ^ b[y[i]]){
            add(b[x[i]] , b[y[i]]);
        }
    }
    for(int i=head[b[1]];i;i=e[i].nxt){
        int v = e[i].v;
        back[v] = 1;
    }
    dp(dis1);
    
    memset(head,0,sizeof head);cnt = 0;
    memset(back,0,sizeof back);
    for(int i=1;i<=m;++i){
        if(b[x[i]] ^ b[y[i]]){
            add(b[y[i]] , b[x[i]]);
        }
    }
    for(int i=head[b[1]];i;i=e[i].nxt){
        int v = e[i].v;
        back[v] = 1;
    }
    dp(dis2);
    
    for(int i=1;i<=Bcnt;++i){
        if(!dis1[i]) continue;
        for(int j=head[i];j;j=e[j].nxt){
            int v = e[j].v;
            if(!dis2[v]) continue;
            ans = max(ans , (dis1[i] + dis2[v] - size[b[1]]));
        }
    }
    printf("%d",ans);
    return 0;
}
posted @ 2018-10-04 18:52  lajioj  阅读(207)  评论(0编辑  收藏  举报