hdu2767 强连通

本文详细阐述了如何通过增加特定数量的边使图变为强连通,并提供了相应的算法实现。通过DAG的概念,文章指出只需考虑入度为0和出度为0的节点对增边的需求,通过tarjan算法识别强连通分量并计算所需边的数量。

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

题意是加多少条边能使图成为强连通。。。。

将一个强连通分量缩成一个点,构成一个DAG,添加至少max(入度为0的个数,出度为0的个数)条边即可,原因不好解释。。DAG每个入度不为0的点可以由某个入度为0的点出发到达(yy一下就能明白),把出度为0的点连向入度为0的点即可。。max(入度为0的个数,出度为0的个数)

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
struct node
{
    int u,v;
};
node e[100000];
int first[55555],next[100000];
int cc,flag[55555],dfn[55555],low[55555];
int sum,top,stack[55555];
int in[55555],out[55555],time;
inline void add_edge(int u,int v)
{
    e[cc].u=u;
    e[cc].v=v;
    next[cc]=first[u];
    first[u]=cc;
    cc++;
}
int tardfs(int s)
{
    flag[s]=1;
    low[s]=dfn[s]=time++;
    stack[++top]=s;
    int i;
    for(i=first[s];i!=-1;i=next[i])
    {
        if(flag[e[i].v]==0)
            tardfs(e[i].v);
        if(flag[e[i].v]==1)
            low[s]=min(low[e[i].v],low[s]);
    }
    if(dfn[s]==low[s])
    {
        ++sum;
        do
        {
            low[stack[top]]=sum;
            flag[stack[top]]=2;
        }while(stack[top--]!=s);
    }
    return 0;
}
int tarjan(int n)
{
    sum=0;
    time=1;
    memset(flag,0,sizeof(flag));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    int i;
    top=0;
    for(i=1;i<=n;i++)
    {
        if(flag[i]==0)
            tardfs(i);
    }
    if(sum==1)
        return 0;
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    for(i=1;i<=n;i++)
    {
        int j;
        for(j=first[i];j!=-1;j=next[j])
        {
            if(low[e[j].v]!=low[e[j].u])
            {
                out[low[e[j].u]]++;
                in[low[e[j].v]]++;
            }
        }
    }
    int res1=0,res2=0;
    for(i=1;i<=sum;i++)
    {
        if(in[i]==0)
            res1++;
        if(out[i]==0)
            res2++;
    }
    return max(res1,res2);
}
int main()
{
    int tt;
    scanf("%d",&tt);
    while(tt--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        memset(first,-1,sizeof(first));
        memset(next,-1,sizeof(next));
        int i;
        cc=0;
        for(i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
        }
        int  ans=tarjan(n);
        printf("%d\n",ans);

    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值