poj 2553 强连通求出度为零的点集合

本文介绍了一种用于检测有向图中汇点的算法,并提供了一个完整的C++实现示例。该算法通过深度优先搜索(DFS)来确定哪些节点能够从所有可达节点接收回路,即汇点。

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

定义:点v是汇点须满足 --- 对图中任意点u,若v可以到达u则必有u到v的路径;若v不可以到达u,则u到v的路径可有可无。
题意:在n个点m条边的有向图里面,问有多少个点是汇点。
#include<stdio.h>
#include<string.h>
#include<stack>
#include<queue>
#include<algorithm>
using namespace std;
#define ll long long
#define me(a,b) memset(a,b,sizeof(a))
struct node
{
    int u,v,next;
} e[100005];
int dfn[5005],low[5005],head[5005],scnt[5005],book[5005],out[5005],ans[5005];
int tot,cnt,top;
void add(int u,int v)
{
    e[top].u=v;
    e[top].v=u;
    e[top].next=head[u];
    head[u]=top++;
}
stack<int>q;
int n,m;
int trijan(int x)
{
    dfn[x]=low[x]=++tot;
    q.push(x);
    for(int i=head[x];i!=-1;i=e[i].next)
    {
        int u=e[i].u;
        if(!dfn[u])
        {
            trijan(u);
            low[x]=min(low[u],low[x]);
        }
        else if(!scnt[u])low[x]=min(low[x],dfn[u]);
    }
    if(low[x]==dfn[x])
    {
        int v=-1;
        cnt++;
        while(v!=x)
        {
            v=q.top();
            q.pop();
            scnt[v]=cnt;
        }
    }
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        scanf("%d",&m);
        me(head,-1);
        top=cnt=tot=0;
        me(dfn,0);
        me(low,0);
        me(scnt,0);
        me(book,0);
        me(out,0);
        for(int i=0;i<m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);
        }
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])
                trijan(i);
        }
        for(int j=1;j<=n;j++)
        {
            book[scnt[j]]++;
        }
        for(int i=0;i<top;i++)
        {
            if(scnt[e[i].u]!=scnt[e[i].v])
            {
                //printf("%d    ...\n",e[i].v);
                out[scnt[e[i].v]]++;
            }
        }
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            if(!out[scnt[i]])
            {
                ans[sum++]=i;
            }
        }
        for(int i=0;i<sum;i++)
        {
            if(!i)
            {
                printf("%d",ans[i]);
            }
            else printf(" %d",ans[i]);
        }
        printf("\n");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值