• Tarjan求缩点化强连通图


    Describe:

      求一个有向图加多少条边可以变成一个强连通图

    Solution:

      Tarjan缩点染色后,判断出度和入度,所有点的出度 = 0 的和 和 入度 = 0 的和的最大值即为所求。

    缩点染色

    for(int i = 1;i <= n;++i)
            {
                if(!dfn[i])
                {
                    tarjan(i);
                }
            }
    
    void tarjan(int s)
    {
        dfn[s] = low[s] = ++tot;
        stk[stk_siz++] = s;
        instk[s] = true;
    
        for(int i = id[s];~i;i = e[i].pre)
        {
            int to = e[i].to;
            if(!dfn[to])
            {
                tarjan(to);
                low[s] = min(low[s],low[to]);
            }
            else if(instk[to])
                low[s] = min(low[s],dfn[to]);
        }
        if(dfn[s] == low[s])
        {
            ++colid;
            while(stk_siz > 0 && stk[stk_siz] != s)
            {
                --stk_siz;
                int tmp = stk[stk_siz];
                instk[tmp] = false;
                col[tmp] = colid;
            }
        }
    }
    

     进行每一个缩点后的出度入度判断

    for(int i = 0;i < m;++i)
            {
                from = e[i].from;
                to = e[i].to;
                //咋忘了缩点了!!这是缩点后的操作
    //            cout<<from<<" "<<to<<endl;
    //            cout<<col[from]<<" "<<col[to]<<endl;
                if(col[from] != col[to])
                {
                    in[col[to]]++;
                    out[col[from]]++;
                }
            }
            int ret = 0,innum = 0,outnum = 0;
            for(int i = 1;i <= colid;++i)
            {
                if(!in[i])innum++;
                if(!out[i])outnum++;
            }
            ret = max(innum,outnum);
    

     还要注意的就是缩成一个点的时候,也就是本来就是一个强连通分量是不需要添加边的

    Coding:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    const int maxn = 2e4 + 1e3;
    const int maxm = 5e4 + 1e3;
    struct node{
        int from,to,pre;
        node(){}
        node(int to,int pre):to(to),pre(pre){}
    }e[maxm];
    int colid;
    int id[maxn],cnt;
    int col[maxn];
    int in[maxn],out[maxn];
    int dfn[maxn],low[maxn];
    int tot;
    int stk[maxn],stk_siz;
    
    bool instk[maxn];
    void add(int from,int to)
    {
        e[cnt].to = to;
        e[cnt].from = from;
        e[cnt].pre = id[from];
        id[from] = cnt++;
    }
    void init()
    {
        memset(id,-1,sizeof(id));
        memset(instk,0,sizeof(instk));
        memset(dfn,0,sizeof(dfn));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        cnt = tot = colid = stk_siz = 0;
    }
    void tarjan(int s)
    {
        dfn[s] = low[s] = ++tot;
        stk[stk_siz++] = s;
        instk[s] = true;
    
        for(int i = id[s];~i;i = e[i].pre)
        {
            int to = e[i].to;
            if(!dfn[to])
            {
                tarjan(to);
                low[s] = min(low[s],low[to]);
            }
            else if(instk[to])
                low[s] = min(low[s],dfn[to]);
        }
        if(dfn[s] == low[s])
        {
            ++colid;
            while(stk_siz > 0 && stk[stk_siz] != s)
            {
                --stk_siz;
                int tmp = stk[stk_siz];
                instk[tmp] = false;
                col[tmp] = colid;
            }
        }
    }
    int main()
    {
        int t,n,m;
        scanf("%d",&t);
        while(t--)
        {
            init();
            scanf("%d%d",&n,&m);
            int from,to;
            for(int i = 1;i <= m;++i)
            {
                scanf("%d%d",&from,&to);
                add(from,to);
            }
            for(int i = 1;i <= n;++i)
            {
                if(!dfn[i])
                {
                    tarjan(i);
                }
            }
            //边的存储是从1开始!!
            for(int i = 0;i < m;++i)
            {
                from = e[i].from;
                to = e[i].to;
                //咋忘了缩点了!!这是缩点后的操作
    //            cout<<from<<" "<<to<<endl;
    //            cout<<col[from]<<" "<<col[to]<<endl;
                if(col[from] != col[to])
                {
                    in[col[to]]++;
                    out[col[from]]++;
                }
            }
            int ret = 0,innum = 0,outnum = 0;
            for(int i = 1;i <= colid;++i)
            {
                if(!in[i])innum++;
                if(!out[i])outnum++;
            }
            ret = max(innum,outnum);
            //特殊判断一下,一个点的时候(一种颜色的时候就是强连通了)
            if(colid == 1)
                printf("%d
    ",0);
            else
                printf("%d
    ",ret);
        }
        return 0;
    }
    

      

  • 相关阅读:
    arcmap发布服务报错:“Faild to publish service”
    GIS优秀博客以及网址收藏,持续更新
    AE实现拖拽
    【ArcGIS for Server】制作并发布GP服务--缓冲分析为例
    ArcGIS API for JavaScript经典例子
    ArcGIS API for JavaScript
    Console ArcEngine 许可绑定
    FK JavaScript:ArcGIS JavaScript类库加载不成功而导致的程序异常
    FK JavaScript之:ArcGIS JavaScript添加Graphic,地图界面却不显示
    ASP.NET发布后,功能不响应
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/9615615.html
Copyright © 2020-2023  润新知