hdu3836 Equivalent Sets(有向图至少添加多少条边才能变为强连通图+tarjan缩点)

该博客探讨了如何解决有向图问题,即确定至少需要添加多少条边才能使给定的有向图变成强连通图。解题方法是结合tarjan缩点算法和有向无环图(DAG)的性质。如果图中存在入度为0的节点数量为a,出度为0的节点数量为b,则至少需要添加max(a, b)条边。当图本身是强连通图或仅包含一个节点时,无需添加边。" 133163006,19671414,测试网络连通性:ping与telnet命令及Python实现,"['网络', '服务器', '编程', 'linux']

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

题目链接:点击打开链接

题意描述:对于给定的有向图,至少要添加多少条边,才能使之成为强连通图

解题思路:tarjan缩点+DAG性质

1、DAG性质:对于一个有向无环图,若想让它成为强连通图,至少需要添加max(a,b) a为入度为0的边点的数量,b为出度为0的点的数量

2、通过tarjan缩点将普通的有向图转换为有向无环图,注意当图本身就是强连通时(如只有1个点)时不需要添加边


代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#define MAXN 20010
#define MAXE 50010
using namespace std;
int head[MAXN],tot1,tot2;
struct Edge{
    int u,v,next;
}e1[MAXE],e2[MAXN];
void addEdge(int u,int v,Edge* edge,int& tol){
    edge[tol].u=u;edge[tol].v=v;
    edge[tol].next=head[u];head[u]=tol++;
}
int n,m;
int low[MAXN],dfn[MAXN],stack[MAXN],belong[MAXN],num[MAXN];
bool instack[MAXN];
int scc,top,index;
void Tarjan(int u){
    int v;
    low[u]=dfn[u]=++index;
    stack[top++]=u;
    instack[u]=true;
    for(int i=head[u];i!=-1;i=e1[i].next){
        v=e1[i].v;
        if(!dfn[v]){
            Tarjan(v);
            if(low[u]>low[v]) low[u]=low[v];
        }
        else if(instack[v]&&low[u]>dfn[v])
            low[u]=dfn[v];
    }
    if(low[u]==dfn[u]){
        ++scc;
        do{
            v=stack[--top];
            instack[v]=false;
            belong[v]=scc;
            num[scc]++;
        }while(u!=v);
    }
}
int inde[MAXN],outde[MAXN];
void solve(){
    memset(dfn,0,sizeof(dfn));
    memset(instack,false,sizeof(instack));
    memset(num,0,sizeof(num));
    scc=top=index=0;
    for(int i=1;i<=n;++i)
        if(!dfn[i]) Tarjan(i);
    tot2=0;memset(head,-1,sizeof(head));
    memset(inde,0,sizeof(inde));
    memset(outde,0,sizeof(outde));
    int u,v;
    for(int i=0;i<m;++i){
        u=belong[e1[i].u];
        v=belong[e1[i].v];
        if(u!=v){
            addEdge(u,v,e2,tot2);
            inde[v]++;
            outde[u]++;
        }
    }
    int a=0,b=0;
    for(int i=1;i<=scc;++i){
        if(!inde[i]) a++;
        if(!outde[i]) b++;
    }
    if(scc==1)printf("0\n");///特殊情况当图本身为强联通图时,输出0
    else
        printf("%d\n",max(a,b));
}
int main()
{
    while(scanf("%d%d",&n,&m)==2){
        tot1=0;memset(head,-1,sizeof(head));
        int u,v;
        for(int i=0;i<m;++i){
            scanf("%d%d",&u,&v);
            addEdge(u,v,e1,tot1);
        }
        solve();
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值