• 强联通总结


    noip前两天开始学这玩意…………

    强连通(模版 元问题byscy)

    模板题,我感觉不难。

    另外可以用来缩点,在开一个邻接表,不再在一个强联通分量的连边就好。

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 2e4 + 10;
    const int MAXM = 2e5 + 10;
    struct Edge{ int to, next; } e[MAXM];
    int head[MAXN], tot, n, m;
    
    int low[MAXN], dfn[MAXN], id;
    int belong[MAXN], ins[MAXN], cnt;
    int sta[MAXN], top;
    
    void AddEdge(int from, int to)
    {
        e[tot] = Edge{to, head[from]};
        head[from] = tot++;
    }
    
    void tarjan(int u)
    {
        low[u] = dfn[u] = ++id;
        sta[++top] = u; ins[u] = 1;
        for(int i = head[u]; ~i; i = e[i].next)
        {
            int v = e[i].to;
            if(!dfn[v])
            {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if(ins[v]) low[u] = min(low[u], low[v]);
        }
        
        if(dfn[u] == low[u])
        {
            ++cnt;
            while(1)
            {
                int v = sta[top--];
                ins[v] = 0;
                belong[v] = cnt;
                if(u == v) break;
            }
        }
    }
    
    int main()
    {
        memset(head, -1, sizeof(head)); tot = 0;
        scanf("%d%d", &n, &m);
        _for(i, 1, m)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            AddEdge(u, v);
        }
        
        _for(i, 1, n)
            if(!dfn[i])
                tarjan(i);
        printf("%d
    ", cnt);
        
        return 0;
    }

    强连通入门2:添加最少边成为强连通图

    看题的时候感觉是一个公式

    但是想复杂了,1h推出一个错误的结论……

    这样想,如果是强联通图,肯定每个点的出度和入度都至少为1

    那么我们把出度和入度为0的点消灭就好了

    一条边可以消灭一个入度为0的点和1个出度为0的点

    设s1为入度为0的点,s2为出度为0的点

    那么用min(s1, s2)条边连接入度为0的点和出度为0的点

    然后用max(s1, s2) - min(s1, s2)条边消灭剩下的点

    所以答案是max(s1, s2)

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 2e4 + 10;
    const int MAXM = 2e5 + 10;
    struct Edge{ int to, next; } e[MAXM];
    int head[MAXN], tot;
    
    int dfn[MAXN], low[MAXN], id;
    int sta[MAXN], ins[MAXN], top;
    int belong[MAXN], n, m, cnt;
    int in[MAXN], out[MAXN];
    
    void AddEdge(int from, int to)
    {
        e[tot] = Edge{to, head[from]};
        head[from] = tot++;
    }
    
    void tarjan(int u)
    {
        dfn[u] = low[u] = ++id;
        sta[++top] = u; ins[u] = 1;
        
        for(int i = head[u]; ~i; i = e[i].next)
        {
            int v = e[i].to;
            if(!dfn[v])
            {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if(ins[v]) low[u] = min(low[u], low[v]);
        }
        
        if(dfn[u] == low[u])
        {
            cnt++;
            while(1)
            {
                int v = sta[top--];
                ins[v] = 0;
                belong[v] = cnt;
                if(u == v) break;
            }
        }
    }
    
    void init()
    {
        tot = cnt = id = top = 0;
        memset(head, -1, sizeof(head)); 
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(ins, 0, sizeof(ins));
           memset(in, 0, sizeof(in));
        memset(out, 0, sizeof(out));
    }
    
    int main()
    {
        int T;
        scanf("%d", &T);
        
        while(T--)
        {
            init();
            scanf("%d%d", &n, &m);
            _for(i, 1, m)
            {
                int u, v;
                scanf("%d%d", &u, &v);
                AddEdge(u, v);
            }
            
            _for(i, 1, n)
                if(!dfn[i])
                    tarjan(i);
            
            _for(u, 1, n)
                for(int i = head[u]; ~i; i = e[i].next)
                {
                    int v = e[i].to;
                    int uu = belong[u], vv = belong[v]; //新的点 
                    if(uu == vv) continue;
                    out[uu]++; in[vv]++;
                }
            
            if(cnt == 1) { puts("0"); continue; } //特判 
                
            int ans1 = 0, ans2 = 0;
            _for(i, 1, cnt) 
            {
                ans1 += (in[i] == 0);
                ans2 += (out[i] == 0);
            }
            printf("%d
    ", max(ans1, ans2));
        }
        
        return 0;
    }

    强连通入门4:The Bottom of a Graph

    一开始以为看这个点出去的点和自己是不是连通分量就好了

    然后一直WA

    然后发现这个点能达到的点不只这个点出去的点……这样做是错的……

    答案应该是缩点后出度为0的连通分量的所有点

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++) 
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++) 
    using namespace std;
    
    const int MAXN = 5e3 + 10;
    struct Edge{ int to, next; };
    vector<Edge> e;
    int head[MAXN], tot;
    int n, m;
    
    int sta[MAXN], ins[MAXN], belong[MAXN], top;
    int dfn[MAXN], low[MAXN], out[MAXN], id, cnt;
    
    void AddEdge(int from, int to)
    {
        e.push_back(Edge{to, head[from]});
        head[from] = tot++;
    }
    
    void init()
    {
        tot = id = top = cnt = 0;
        e.clear();
        memset(head, -1, sizeof(head));
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(ins, 0, sizeof(ins));
        memset(out, 0, sizeof(out));
    }
    
    void tarjan(int u)
    {
        dfn[u] = low[u] = ++id;
        sta[++top] = u; ins[u] = 1;
        
        for(int i = head[u]; ~i; i = e[i].next)
        {
            int v = e[i].to;
            if(!dfn[v])
            {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if(ins[v]) low[u] = min(low[u], low[v]);
        }
        
        if(dfn[u] == low[u])
        {
            ++cnt;
            while(1)
            {
                int v = sta[top--];
                ins[v] = 0;
                belong[v] = cnt;
                if(u == v) break;
            }
        }
    }
    
    
    int main()
    {
        while(~scanf("%d", &n) && n)
        {
            init();
            scanf("%d", &m);
            _for(i, 1, m)
            {
                int u, v;
                scanf("%d%d", &u, &v);
                AddEdge(u, v);
            }
            
            _for(i, 1, n)
                if(!dfn[i])
                    tarjan(i);
            
            _for(u, 1, n)
                for(int i = head[u]; ~i; i = e[i].next)
                {
                    int v = e[i].to;
                    int uu = belong[u], vv = belong[v];
                    if(uu != vv) out[uu]++;
                }
            
            int first = 1;
            set<int> ans;
            _for(i, 1, cnt) if(!out[i]) ans.insert(i);
            _for(i, 1, n)
                if(ans.count(belong[i]))
                {
                    if(first) first = 0; else putchar(' ');
                    printf("%d", i);
                }
            puts("");
        }
        
        return 0;
    }

    还差两道题,待补……

  • 相关阅读:
    算法第四章上机实践报告
    算法第三章作业
    算法第三章上机实践报告
    算法第二章总结
    关于stl::sort--算法第二章作业
    算法第二章上机实践报告
    算法第一章作业
    1
    2020-2021-1 20209302毕慧敏《Linux内核原理与分析》第十二周作业
    2020-2021-1 20209302毕慧敏《Linux内核原理与分析》第十一周作业
  • 原文地址:https://www.cnblogs.com/sugewud/p/9931546.html
Copyright © 2020-2023  润新知