Gym - 101170B - British Menu (tarjan縮點 + 拓撲最長路)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 +10;
int n,m,ans;
vector<int> e[maxn],ee[maxn],vec[maxn];
int dfn[maxn],low[maxn],sta[maxn],ma[maxn];
int num,top,cnt;
bool vis[maxn];
int f[maxn],d[maxn],dis[maxn],tmp[maxn],g[5][5];
queue<int>que;
void tarjan(int x)
{
    dfn[x] = low[x] = ++num;
    vis[x] = 1;
    sta[++top] = x;
    for(int i = 0; i < e[x].size(); i++)
    {
        int j = e[x][i];
        if(!dfn[j])
        {
            tarjan(j);
            low[x] = min(low[x],low[j]);
        }
        else if(vis[j])
        {
            low[x] = min(low[x],dfn[j]);
        }
    }
    if(low[x] == dfn[x])
    {
        int tmp,k = 0;
        cnt++;
        while(1)
        {
            tmp = sta[top--];
            vis[tmp] = 0;
            f[tmp] = k++;//改點在其縮點內的編號
            vec[cnt].push_back(tmp);//縮點內的點有哪些
            ma[tmp] = cnt;//該點屬於幾號縮點
            if(tmp == x)break;
        }
    }
}
void dfs(int x,int s,int w)//判斷縮點內點的距離關係
{
   g[f[s]][f[x]] = max(g[f[s]][f[x]],w);
   vis[x] = 1;
   for(int i = 0  ; i < ee[x].size();i++)
   {
       int j = ee[x][i];
       if(!vis[j])
       {
           dfs(j,s,w+1);
       }
   }
   vis[x] = 0;
}
void init()
{
    cnt = num = top = 0;
    memset(dfn,0,sizeof dfn);
    memset(vis,0,sizeof vis);
}
int main()
{
    init();
    ios::sync_with_stdio(0);
    cin>>n>>m;
    for(int i = 1;i <= m;  i++)
    {
        int x,y;
        cin>>x>>y;
        e[x].push_back(y);
    }
    for(int i = 1;i <= n; i++)
    {
        if(!dfn[i])
        {
            tarjan(i);
        }
    }
    for(int i = 1;i <= n; i++)
    {
        for(int j = 0; j < e[i].size();j++)
        {
            int t = e[i][j];
            if(ma[i] == ma[t])
            {
                ee[i].push_back(t);
            }
            else
            {
                d[ma[t]]++;//縮點入度加一
            }
        }
    }
    for(int i  =1;i <= cnt; i++)
    {
        if(d[i] == 0)
        {
            que.push(i);//沒有入度的點作爲
        }
    }
    while(!que.empty())//拓撲
    {
        int now =  que.front();que.pop();
        memset(g,0,sizeof g);

        //沒入度縮點內部任意點之間的距離
        for(int i = 0; i < vec[now].size(); i++)
        {
            int j = vec[now][i];
            dfs(j,j,0);
        }
        for(int i = 0  ; i < vec[now].size();i++)
        {
            for(int j =  0; j < vec[now].size();j++)
            {
                tmp[vec[now][i]] = max(tmp[vec[now][i]],dis[vec[now][j]]+g[f[vec[now][j]]][f[vec[now][i]]]);
            }
        }
        for(int i =  0 ;  i < vec[now].size(); i++)
        {
            dis[vec[now][i]] = tmp[vec[now][i]];
        }
        for(int i =  0 ;  i < vec[now].size();i++)
        {
            int ii = vec[now][i];
            for(int j = 0; j < e[ii].size();j++)
            {
                int jj = e[ii][j];
                if(ma[ii]!=ma[jj])
                {
                    dis[jj] = max(dis[jj],dis[ii]+1);
                    d[ma[jj]]--;
                    if(d[ma[jj]] == 0)
                    {
                        que.push(ma[jj]);
                    }
                }
            }
        }

    }
    for(int i = 1; i<= n; i++)
        ans = max(ans,dis[i]);
    cout<<ans+1<<endl;
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章