两种代码风格解决强连通分量解决加多少条边使整个图连通&多少个点可以到达所有点

使用Tarjan进行缩点,得到一个SCC图、
这个图有多少个入度为0的,多少个出度为0的。

假设有n个入度为0,m个出度为0

那么需要给n个点才能传遍所有点,需要加max(n,m)条边才能使整个图变成强连通分量

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<stack>
#include<string>

//#include<bits/stdc++.h>
using namespace std;
const int maxn=110;

struct Node{
    int to,next;
}edge1[maxn*100],edge2[maxn*100];

int head1[maxn],head2[maxn];
int mark1[maxn],mark2[maxn];
int tot1,tot2;
int num,setNum[maxn];
int cnt1,cnt2,st[maxn],belong[maxn];
struct Edge{
    int l,r;
}e[maxn*100];

void add(int a,int b)
{
    edge1[tot1].to=b;edge1[tot1].next=head1[a];head1[a]=tot1++;
    edge2[tot2].to=a;edge2[tot2].next=head2[b];head2[b]=tot2++;
}

void DFS1(int x)
{
    mark1[x]=1;
    for(int i=head1[x];i!=-1;i=edge1[i].next)
        if(!mark1[edge1[i].to])DFS1(edge1[i].to);
    st[cnt1++]=x;
}

void DFS2(int x)
{
    mark2[x]=1;
    num++;
    belong[x]=cnt2;
    for(int i=head2[x];i!=-1;i=edge2[i].next)
        if(!mark2[edge2[i].to])DFS2(edge2[i].to);
}

int main()
{
    int n,m;
    while(scanf("%d",&n)!=EOF)
    {
        int w,v;
        tot1=tot2=1;
        for(int i=1;i<=n;i++)
        {
            head1[i]=head2[i]=-1;
            mark1[i]=mark2[i]=0;
        }
        m=0;
        for(w=1;w<=n;w++)
        {
            while(scanf("%d",&v)&&v){
                m++;e[m].l=w,e[m].r=v;
                add(w,v);
            }
        }
        cnt1=cnt2=1;
        for(int i=1;i<=n;i++){
            if(!mark1[i])DFS1(i);
        }
        for(int i=cnt1-1;i>=1;i--)
        {
            if(!mark2[st[i]])
            {
                num=0;
                DFS2(st[i]);
                setNum[cnt2++]=num;
            }
        }
        int out[maxn],in[maxn];//计算出度和入度
        memset(out,0,sizeof(out));
        memset(in,0,sizeof(in));
        for(int i=1;i<=m;i++)
        {
            if(belong[e[i].l]!=belong[e[i].r])
            {
                out[belong[e[i].l]]++;
                in[belong[e[i].r]]++;
            }
        }
        int res1=0;//出度为0的个数
        int res2=0;//入度为0的个数
        for(int i=1;i<cnt2;i++)
        {
            if(!out[i]) res1++;
            if(!in[i])  res2++;
        }
        //下面这个是关键,整张图就一个连通分量时,输出0,1.WR了好几次呢
        if(cnt2==2) {printf("1
0
");continue;}
        printf("%d
",res2);
        printf("%d
",res1>res2?res1:res2);
    }
    return 0;
}

第二种Tarjan求解!!

#include <algorithm>  
    #include <iostream>  
    #include <sstream>  
    #include <cstring>  
    #include <cstdlib>  
    #include <string>  
    #include <vector>  
    #include <cstdio>  
    #include <stack>  
    #include <cmath>  
    #include <queue>  
    #include <map>  
    #include <set>  
    using namespace std;  
    #define N 105  

    vector<int> e[N];  
    int dfn[N], low[N],stap[N], stop,belong[N],outdeg[N],indeg[N],dindex, cnt;  
    bool instack[N];  
    int n, m;  

    void tarjan(int x){  
        int y = 0;  
        dfn[x]=low[x]=++dindex;  
        instack[x]=true;  
        stap[++stop]=x;  
        for (int i=0; i<e[x].size(); i++) {  
            y=e[x][i];  
            if (!dfn[y]) {  
                tarjan(y);  
                if (low[y]<low[x]) {  
                    low[x]=low[y];  
                }  
            }  
            else if (instack[y]&&dfn[y]<low[x]){  
                low[x]=dfn[y];  
            }  
        }  
        if (dfn[x]==low[x]) {  
            cnt++;  
            while (y!=x) {  
                y=stap[stop--];  
                instack[y]=false;  
                belong[y]=cnt;  
            }  
        }  
    }  

    void solve(){  
        stop=dindex=cnt=0;  
        memset(dfn, 0, sizeof(dfn));  
        memset(instack, 0, sizeof(instack));  
        memset(outdeg, 0, sizeof(outdeg));  
        memset(indeg, 0, sizeof(indeg));  
        for (int i=1; i<=n; i++) {  
            if (!dfn[i]) {  
                tarjan(i);  
            }  
        }  
    }  

    int main(){  
        int temp;  
        while (~scanf("%d", &n)) {  
            for (int i=1; i<=n; ++i) {  
                e[i].clear();  
            }  
            for (int i=1; i<=n; i++) {  
                while (scanf("%d",&temp)) {  
                    if (temp==0) {  
                        break;  
                    }  
                    e[i].push_back(temp);  
                }  
            }  
            solve();  
            for (int i=1; i<=n; i++) {  
                int size=e[i].size();  
                for (int j=0; j<size; j++) {  
                    if (belong[i]!=belong[e[i][j]]) {  
                        outdeg[belong[i]]++;  
                        indeg[belong[e[i][j]]]++;  
                    }  
                }  
            }  
            int sumout=0,sumin=0;  
            for (int i=1; i<=cnt; i++) {  
                if (outdeg[i]==0) {  
                    sumout++;  
                }  
                if (indeg[i]==0) {  
                    sumin++;  
                }  
            }  
            if (cnt==1) {  
                printf("1
0
");  
            }  
            else  
            printf("%d
%d
",sumin,max(sumin,sumout));  

        }  
        return 0;  
    }  
原文地址:https://www.cnblogs.com/wlxtuacm/p/5712276.html