加载中...

一个图变成强联通分量需要加几条边 结论 加max(p ,q )的边就可以

第一问:给几个点传信息那么图的所有点都可以街道(看看起点p有几个点就可以了)
第二问:一个图变成强联通分量需要加几条边
结论 加max(p ,q )的边就可以

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N =110, M=1e4+10;
int n;
int h[N], e[M], ne[M], idx;
int dfn[N],low[N],timestamp;
int stk[N],top;
bool in_stk[N];
int id[N],scc_cnt;
int din[N],dout[N];
void add(int a, int b)  // 添加一条边a->b
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void tarjan(int u){
    dfn[u]=low[u]=++timestamp;
    stk[++top]=u,in_stk[u]=true;
    for (int i = h[u]; ~i ; i =ne[i] ){
        int j=e[i];
        if(!dfn[j]){
            tarjan(j);
            low[u]=min(low[u],low[j]);
        }else if(in_stk[j]) {//搜过了 说明是回去的边
            low[u]=min(low[u],dfn[j]);
        }
    }
    if(dfn[u]==low[u]){
        ++scc_cnt;
        int y;
        do{
            y=stk[top--];
            in_stk[y]=false;
            id[y]=scc_cnt;
        }while(y!=u);
    }
}
int main()
{
    cin>>n;
    memset(h, -1, sizeof h);
    for (int i = 1; i <= n; i ++ ){
        int t;
        while ( cin>>t ,t) add(i, t);
    }
    for (int i = 1; i <= n; i ++ )
    if(!dfn[i])
    tarjan(i);
    
    for (int i = 1; i <= n; i ++ ){//对于每条边
        for (int j = h[i]; j != -1; j =ne[j] ){
            int k=e[j];
            int a=id[i],b=id[k];//如果边的两端不是一个连通块那就处理下 
            if(a!=b){
                dout[a]++;
                din[b]++;
            }
        }
    }
    int a=0,b=0;//统计缩点后 起点和终点的个数
    for (int i = 1; i <= scc_cnt; i ++ ){//对于缩点后的每个点
        if(!din[i]) a++;
        if(!dout[i]) b++;
    }
    cout << a<<endl;
    if(scc_cnt==1){
        cout << 0<<endl;
    }else {
        cout << max(a,b)<<endl;
    }
    return 0;
}
posted @ 2022-08-30 20:52  liang302  阅读(25)  评论(0编辑  收藏  举报