Problem F. A-maze-ing-----“今日头条”杯2018年湖北省赛(网络赛)

本文介绍了一道算法竞赛题目“A-maze-ing”的解题思路。通过使用Trajan算法进行缩点处理,并利用深度优先搜索(DFS)来找出包含点数最多的路径。文章详细解释了如何构建图、进行缩点及最终求解的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

“今日头条”杯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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值