洛谷P3119 [USACO15JAN]Grass Cownoisseur G tarjan+spfa

题目链接:https://www.luogu.com.cn/problem/P3119

首先肯定是要用tarjan缩点的,这样图上就不会有环了,你所需做的就是加一条边的反向边,使这张图能有以 1 为起点 和 终点的环并且这个环要尽可能大。我在洛谷的题解里看到一个非常巧妙的做法,我们可以将缩完点的图复制一下,形成上下两层相同的图,下层每个点的编号是上层每个点编号+col_id(强连通分量的数量),然后上层对于每条从 v 到 u 的边,加一条从 u 到 v+col_id 的边。例如下图
在这里插入图片描述
我们每次走红边,就不可能回到黑边,所以走红边就相当于一次逆行。最后我们只需跑一次以 col[1] (包含1的强连通分量) 为起点的spfa即可,答案就是 1 到 1’ 的距离。
代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int maxm=3e5+5;
struct node
{
    int to,next;
}edge1[maxn],edge2[maxm];
int cnt1,cnt2;
int head1[maxn],head2[maxm];
int stc[maxn],dfn[maxn],low[maxn];
int col[maxn];
int col_num[maxm];
bool vis[maxn];
int top,dfn_num,col_id;
void add1(int x,int y)
{
    edge1[++cnt1].next=head1[x];
    edge1[cnt1].to=y;
    head1[x]=cnt1;
}
void add2(int x,int y)
{
    edge2[++cnt2].next=head2[x];
    edge2[cnt2].to=y;
    //edge2[cnt2].w=c;
    head2[x]=cnt2;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++dfn_num;
    stc[++top]=u;
    vis[u]=1;
    for(int i=head1[u];i;i=edge1[i].next)
    {
        int v=edge1[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
        low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        vis[u]=false;
        col[u]=++col_id;
        int len=1;
        while(stc[top]!=u)
        {
            len++;
            vis[stc[top]]=false;
            col[stc[top--]]=col_id;
        }
        top--;
        col_num[col_id]=len;
    }
}
int dis[maxm];
queue<int>q;
bool tag[maxm];
int n,m;
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        add1(x,y);
    }
    for(int i=1;i<=n;i++)
    if(!dfn[i])
    tarjan(i);
    for(int i=1;i<=col_id;i++)
    col_num[i+col_id]=col_num[i];
    for(int i=1;i<=n;i++)
    for(int j=head1[i];j;j=edge1[j].next)
    {
        int v=edge1[j].to;
        if(col[i]!=col[v])//建新图
        {
            add2(col[i],col[v]);
            add2(col[i]+col_id,col[v]+col_id);
            add2(col[v],col[i]+col_id);
        }
    }
    tag[col[1]]=1;
    q.push(col[1]);
    while(!q.empty())
    {
        int u=q.front();
        for(int i=head2[u];i;i=edge2[i].next)
        {
            int v=edge2[i].to;
            if(dis[v]<dis[u]+col_num[u])
            {
                dis[v]=dis[u]+col_num[u];
                if(!tag[v])
                {
                    tag[v]=1;
                    q.push(v);
                }
            }
        }
        q.pop();
        tag[u]=0;
    }
    printf("%d\n",dis[col[1]+col_id]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44491423/article/details/104565311
今日推荐