Problem F. A-maze-ing-----“今日頭條”杯2018年湖北省賽(網絡賽)

“今日頭條”杯2018年湖北省賽(網絡賽):所有題目鏈接

可以提交的鏈接(不知道現在還能進不了,你還要有賬號):傳送門

Problem F. A-maze-ing

這裏寫圖片描述

題目大意:很坑啊,當初讀了半天題,沒讀懂是什麼意思。
給你n個點,m條有向邊,問你:其中一條路中包含點最多是多少。

思路:先用Trajan縮點,然後,深搜找出其中包含點最多的。

代碼:

#include <cstdio>
#include <cstring>
#include <iostream>
#include<queue>
#include<math.h>
#include <string>
#include <algorithm>
#include<stack>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define PI acos(-1.0)

const int maxn=2*1e5+9;

int low[maxn],pre[maxn],sccno[maxn],sccinq[maxn],clock_pre,clock_low;//Trajan算法的
stack<int>s;
int vis[maxn],inq[maxn];//VIS記錄縮點後入度爲0的點,inq記錄從該點開始所有路中包含最多的點是多少個。
int firs[maxn],first[maxn];//firs記錄縮點前的邊,first記錄縮點後的邊
struct node
{
    int v,nex;
} edge[maxn],ed[maxn];

int N,tot;
void get(int u,int v)
{
    edge[N]=(node)
    {
        v,firs[u]
    };
    firs[u]=N++;
}
void get1(int u,int v)
{
    ed[tot]=(node)
    {
        v,first[u]
    };
    first[u]=tot++;
}
void init()//初始化
{
    mem(low,0);
    mem(pre,0);
    clock_pre=clock_low=0;
    mem(firs,-1);
    mem(first,-1);
    mem(vis,0);
    mem(sccinq,0);
    mem(sccno,0);
    N=0;
    mem(inq,0);
    tot=0;
}

void Trajan(int x)//Trajan算法
{
    pre[x]=low[x]=++clock_low;
    s.push(x);
    for(int i=firs[x]; ~i; i=edge[i].nex)
    {
        int v=edge[i].v;
        if(!pre[v])
        {
            Trajan(v);
            low[x]=min(low[v],low[x]);
        }
        else if(!sccno[v])
            low[x]=min(low[x],pre[v]);
    }
    if(low[x]==pre[x])//重新建點
    {
        clock_pre++;
        while(1)
        {
            int y=s.top();
            s.pop();
            sccno[y]=clock_pre;
            sccinq[clock_pre]++;
            if(y==x)
                break;
        }
    }
}

void dfs(int s)//深搜
{
    if(first[s]==-1)
    {
        inq[s]=sccinq[s];
        return ;
    }
    for(int i=first[s]; ~i; i=ed[i].nex)
    {
        int v=ed[i].v;
        if(!inq[v])
            dfs(v);
        inq[s]=max(inq[s],inq[v]+sccinq[s]);
    }
    return ;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=0; i<m; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            get(u,v);
        }
        for(int i=1; i<=n; i++)//縮點
        {
            if(!pre[i])
                Trajan(i);
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=firs[i]; ~j; j=edge[j].nex)
            {
                int u=i,v=edge[j].v;
                if(sccno[u]!=sccno[v])//重新建邊
                    get1(sccno[u],sccno[v]),vis[sccno[v]]=1;
            }
        }
        int ans=0;//記錄答案
        for(int i=1; i<=clock_pre; i++)
        {
            if(!vis[i])//找縮點後,入度爲0的點,因爲一定是從入度爲零的點開始的
            {
                dfs(i);
                ans=max(ans,inq[i]);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
發佈了186 篇原創文章 · 獲贊 14 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章