洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题解

一、题目:

洛谷原题

二、思路:

好题啊。这道题非常好。

我的思路是首先把原图的强连通分量缩点(这是人都能想到),然后就卡壳了。

非常无耻地看了看题解。

因为原题可以逆向,所以我们需要建两个图,这两个图之间的边是逆向的(也就是逆向走的桥梁)。然后跑SPFA最长路即可。

注意数组大小。

代码写的很好看。

三、代码:

#include
#include
#include
#include

#define LL long long
#define mem(s,v) memset(s,v,sizeof(s))
#define FILEIN(s) freopen(s".in","r",stdin)
#define FILEOUT(s) freopen(s".out","w",stdout)
#define FILE(s) FILEIN(s);FILEOUT(s)

using namespace std;

template<class Type>
inline Type read(Type &num){
    Type x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return f*x;
}

const int maxn=200005;

int n,m,head[maxn<<1],tot;

int dfn[maxn],low[maxn],num,cnt,stack[maxn],top,bl[maxn],siz[maxn<<1];
bool ins[maxn];

int head_new[maxn<<1],tot_new;

int dis[maxn<<1];
bool vis[maxn<<1];

struct Edge{
    int y,next;
    Edge(){}
    Edge(int _y,int _n):y(_y),next(_n){}
}e[maxn<<2],e_new[maxn<<2];

queue<int>q;

inline void connect(int x,int y){
    e[++tot]=Edge(y,head[x]);
    head[x]=tot;
}

inline void connect_new(int x,int y){
    e_new[++tot_new]=Edge(y,head_new[x]);
    head_new[x]=tot_new;
}

void Tarjan(int x){
    dfn[x]=low[x]=++num;
    stack[++top]=x;ins[x]=true;
    for(register int i=head[x];i;i=e[i].next){
        int y=e[i].y;
        if(!dfn[y]){
            Tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(ins[y]){
            low[x]=min(low[x],dfn[y]);
        }
    }
    if(dfn[x]==low[x]){
        int y;++cnt;
        do{
            y=stack[top--];ins[y]=false;
            bl[y]=cnt;siz[cnt]++;
        }while(x!=y);
    }
}

inline void spfa(){
    q.push(bl[1]);
    vis[bl[1]]=true;
    while(q.size()){
        int x=q.front();q.pop();vis[x]=false;
        for(register int i=head_new[x];i;i=e_new[i].next){
            int y=e_new[i].y;
            if(dis[y]<dis[x]+siz[x]){
                dis[y]=dis[x]+siz[x];
                if(!vis[y]){
                    q.push(y);vis[y]=true;
                }
            }
        }
    }
    printf("%d\n",dis[bl[1]+cnt]);
}

int main(){
    n=read(n);m=read(m);
    for(register int i=1;i<=m;++i){
        int x=read(x),y=read(y);
        connect(x,y);
    }
    for(register int i=1;i<=n;++i){
        if(!dfn[i])Tarjan(i);
    }
    for(register int i=1;i<=cnt;++i)siz[i+cnt]=siz[i];
    for(register int x=1;x<=n;++x){
        for(register int i=head[x];i;i=e[i].next){
            int y=e[i].y;
            if(bl[y]!=bl[x])
                connect_new(bl[x],bl[y]),
                connect_new(bl[y],bl[x]+cnt),//逆向走的桥梁(两个图之间的桥梁)
                connect_new(bl[x]+cnt,bl[y]+cnt);
        }
    }
    connect_new(bl[1],bl[1]+cnt);
    spfa();
    return 0;
}

贴一张美美的图。完结撒花。

你可能感兴趣的:(考验美术?——图论,计算机偶像——Tarjan)