zoukankan      html  css  js  c++  java
  • 连通性小结(贴一些模板而已)

    感觉学习了第二遍确实比第一遍理解得好很多!!!(Mark一下,hihocoder 52,53,54,55)

    连通性的四个部分:

    1:割点和桥

    2:边的双连通分量

    3:点的双连通分量

    4:有向图的强连通分量

    最重要的显然是第一个,因为后面的基本上都是根据第一个来的吧。

    概念:

    割点:去掉这个点以后使得连通图不再连通

    桥:去掉这条边使得连通图不再连通

    边的双连通分量:双连通分量里面,任意去掉一条边,图仍是连通的

    点的双连通分量:双连通分量里面,任意去掉一个点,图仍是连通的

    有向图的强连通分量:强连通分量中的任意两个点都有至少两条路径可以到达

    基本上所有类型只需要通过一个Tarjan的算法就能够全部实现。

    割点: 1:如果该点为根,那么child > 1那么这个点就是割点

    2:如果该点不为根,那么low[v] >= low[u] 这个点就为割点

    桥: low[v] > low[u] 那么(u,v)的边就是一个桥,特别要注意和割点不同的是根节点的情况,这里不需要特判


    下面的连通分量需要记录功能,所以用stack维护

    边的双连通分量: 如果把该图的所有桥去掉,剩下来的所有连通图都是一个边的双连通分量。只需要满足low[v] > dfn[u] ,那么从栈顶出栈,一直到v的所有点都在一个边的双 连通 分量里面。因为当前节点不太好用v来表示。所有当low[u] == dfn[u]的时候那么出栈到u的所有点都是边的双连通分量。

    点的双连通分量: 割点两边的子图分别是一个点的双连通分量(与边的双连通分量比较地看)。这里出栈的话,就是到当前的节点(割点),需要特别注意的有两个:1,根节 点的判定。2:只找了割点,会发现并不是所有节点都在相应的点的双连通分量里面了,按照割点分完以后,这个时候stack里面剩下的所有边都在一个点的 双连通分量里面。

    有向图的强连通分量:主要是一个缩点的操作。我们把一个强连通分量缩成一个点。然后再重新建图,topo排序一下就可以搞定了。

    割点和桥:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define ll long long
    #define FOR(i,x,y)  for(int i = x;i < y;i ++)
    #define IFOR(i,x,y) for(int i = x;i > y;i --)
    #define N 20020
    #define M 100010
    
    using namespace std;
    
    int pre[N],low[N],head[N],dfs_clock,m,n,edge_cnt;
    int cut[N];
    bool iscut[N];
    bool isedgecut[M<<1];
    
    struct Edge{
        int u,v;
        int nt;
        bool operator < (Edge rhs)  const{
            if(u == rhs.u)  return v < rhs.v;
            return u < rhs.u;
        }
    }edge[M<<1];
    
    Edge edgecut[M<<1];
    
    void AddEdge(int u,int v){
        edge[edge_cnt].u = u;
        edge[edge_cnt].v = v;
        edge[edge_cnt].nt = head[u];
        head[u] = edge_cnt++;
    }
    
    void dfs(int u,int fa){
        low[u] = pre[u] = ++dfs_clock;
        int child = 0;
        for(int i = head[u];i != -1;i = edge[i].nt){
            int v = edge[i].v;
            if(v == fa) continue;
            if(!pre[v]){
                child++;
                dfs(v,u);
                low[u] = min(low[v],low[u]);
                if(low[v] >= pre[u])    iscut[u] = true;
                if(low[v] > pre[u]) isedgecut[i] = true;
            }
            else{
                low[u] = min(low[u],pre[v]);
            }
        }
        if(fa == -1 && child <= 1){
            iscut[u] = false;
        }
    }
    
    int main()
    {
        //freopen("test.in","r",stdin);
        while(~scanf("%d%d",&n,&m)){
            int u,v;
            memset(head,-1,sizeof(head));
            memset(pre,0,sizeof(pre));
            memset(iscut,false,sizeof(iscut));
            memset(isedgecut,false,sizeof(isedgecut));
            FOR(i,0,m){
                scanf("%d%d",&u,&v);
                AddEdge(u,v);
                AddEdge(v,u);
            }
            dfs(1,-1);
            int cut_cnt = 0,edgecut_cnt = 0;
            FOR(i,1,n+1){
                if(iscut[i])    cut[cut_cnt++] = i;
            }
            FOR(i,0,edge_cnt){
                if(isedgecut[i]){
                    edgecut[edgecut_cnt].u = min(edge[i].u,edge[i].v);
                    edgecut[edgecut_cnt++].v = max(edge[i].u,edge[i].v);
                }
            }
            sort(edgecut,edgecut+edgecut_cnt);
            if(cut_cnt){
                printf("%d",cut[0]);
                FOR(i,1,cut_cnt){
                    printf(" %d",cut[i]);
                }
            }
            else printf("Null");
            printf("
    ");
            FOR(i,0,edgecut_cnt){
                printf("%d %d
    ",edgecut[i].u,edgecut[i].v);
            }
        }
        return 0;
    }

    边的双连通分量:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #include <cstdlib>
    #include <stack>
    #define INF (1<<30)
    #define ll long long
    #define FOR(i,x,y)  for(int i = x;i < y;i ++)
    #define IFOR(i,x,y) for(int i = x;i > y;i --)
    #define N 20020
    #define M 100010
    
    using namespace std;
    
    typedef  pair<int,int> pii;
    vector <int> G[N];
    stack <int> s;
    int pos[N],dfn[N],dfs_clock,low[N],n,m,ans,num[N];
    
    void dfs(int u,int fa){
        dfn[u] = low[u] = ++dfs_clock;
        s.push(u);
        FOR(i,0,G[u].size()){
            int v = G[u][i];
            if(!dfn[v]){
                dfs(v,u);
                low[u] = min(low[u],low[v]);
            }
            else if(v != fa){
                low[u] = min(dfn[v],low[u]);
            }
        }
        if(low[u] == dfn[u]){
            int cnt = 0,minx = INF;
            ans++;
            while(!s.empty()){
                num[cnt++] = s.top();
                minx = min(minx,num[cnt-1]);
                s.pop();
                if(num[cnt-1] == u) break;
            }
            FOR(i,0,cnt){
                pos[num[i]] = minx;
            }
        }
    }
    
    int main()
    {
        //freopen("test.in","r",stdin);
        while(~scanf("%d%d",&n,&m)){
            FOR(i,0,N)  G[i].clear();
            int u,v;
            FOR(i,0,m){
                scanf("%d%d",&u,&v);
                G[u].push_back(v);
                G[v].push_back(u);
            }
            memset(dfn,0,sizeof(dfn));
            dfs_clock = 0;
            ans = 0;
            while(!s.empty())   s.pop();
            dfs(1,-1);
            printf("%d
    ",ans);
            printf("%d",pos[1]);
            FOR(i,2,n+1){
                printf(" %d",pos[i]);
            }
            printf("
    ");
        }
        return 0;
    }

    有向图的强连通分量:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #define ll long long
    #define FOR(i,x,y)  for(int i = x;i < y;i ++)
    #define IFOR(i,x,y) for(int i = x;i > y;i --)
    #define N 20020
    #define M 100010
    
    using namespace std;
    
    vector <int> G[N];
    vector <int> NG[N];
    stack  <int> s;
    
    int low[N],dfn[N],dfs_clock,cnt,pos[N],l[M],r[M];
    ll w[N],nw[N],res[N];
    int n,m,ans;
    bool mark[N];
    bool vis[N];
    
    void init(){
        FOR(i,0,N)  G[i].clear();
        FOR(i,0,N)  NG[i].clear();
        dfs_clock = 0;
        cnt = 0;
        memset(dfn,0,sizeof(dfn));
        memset(mark,false,sizeof(mark));
        memset(nw,0,sizeof(nw));
        memset(vis,false,sizeof(vis));
        while(!s.empty())   s.pop();
    }
    
    void dfs(int u){
        dfn[u] = low[u] = ++dfs_clock;
        s.push(u);
        mark[u] = true;
        FOR(i,0,G[u].size()){
            int v = G[u][i];
            if(!dfn[v]){
                dfs(v);
                low[u] = min(low[u],low[v]);
            }
            else if(mark[v]) low[u] = min(low[u],dfn[v]);
        }
        if(low[u] == dfn[u]){
            cnt++;
            while(!s.empty()){
                int tem = s.top(); s.pop();
                pos[tem] = cnt;
                nw[cnt] += w[tem];
                mark[tem] = false;
                if(tem == u) break;
            }
        }
    }
    
    void Build_Graph(){
        FOR(i,0,m){
            if(pos[l[i]] != pos[r[i]])  NG[pos[l[i]]].push_back(pos[r[i]]);
        }
    }
    
    ll solve(){
        queue <int> q;
        q.push(pos[1]);
        memset(res,0,sizeof(res));
        ll ans = nw[pos[1]];
        res[pos[1]] = nw[pos[1]];
        while(!q.empty()){
            int u = q.front();q.pop();
            ans = max(ans,res[u]);
            FOR(i,0,NG[u].size()){
                int v = NG[u][i];
                res[v] = max(res[v],res[u] + nw[v]);
                q.push(v);
            }
        }
        return ans;
    }
    
    int main()
    {
        //freopen("test.in","r",stdin);
        while(~scanf("%d%d",&n,&m)){
            init();
            FOR(i,1,n+1)    cin >> w[i];
            //int u,v;
            FOR(i,0,m){
                scanf("%d%d",&l[i],&r[i]);
                G[l[i]].push_back(r[i]);
            }
            dfs(1);
            Build_Graph();
            cout<<solve()<<endl;
        }
        return 0;
    }

    点的双连通分量:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #include <vector>
    #include <stack>
    #define INF (1<<30)
    #define ll long long
    #define FOR(i,x,y)  for(int i = x;i < y;i ++)
    #define IFOR(i,x,y) for(int i = x;i > y;i --)
    #define N 20020
    #define M 100010
    
    using namespace std;
    
    int n,m;
    
    int head[N],edge_cnt;
    struct Edge{
        int u,v;
        int nt,id;
    }edge[M<<1];
    
    void AddEdge(int u,int v,int id){
        edge[edge_cnt].u = u;
        edge[edge_cnt].v = v;
        edge[edge_cnt].nt = head[u];
        edge[edge_cnt].id = id;
        head[u] = edge_cnt++;
    }
    
    stack <int> s;
    int dfn[N],low[N],dfs_clock,pos[M],cnt,ans[M];
    
    void dfs(int u,int fa){
        dfn[u] = low[u] = ++dfs_clock;
        int child = 0;
        for(int i = head[u];i != -1;i = edge[i].nt){
            int v = edge[i].v;
            if(!dfn[v]){
                s.push(edge[i].id);
                child++;
                dfs(v,u);
                low[u] = min(low[u],low[v]);
                if(fa == -1 && child > 1){
                    cnt ++;
                    int minx = INF;
                    while(!s.empty()){
                        int tem = s.top(); s.pop();
                        pos[tem] = cnt;
                        minx = min(minx,tem);
                        if(tem == edge[i].id) break;
                    }
                    ans[cnt] = minx;
                }
                if(fa != -1 && low[v] >= dfn[u]){
                    cnt ++;
                    int  minx = INF;
                    while(!s.empty()){
                        int tem = s.top(); s.pop();
                        pos[tem] = cnt;
                        minx = min(minx,tem);
                        if(tem == edge[i].id) break;
                    }
                    ans[cnt] = minx;
                }
            }
            else if(v != fa && dfn[v] < dfn[u]){
                s.push(edge[i].id);
                low[u] = min(low[u],dfn[v]);
            }
        }
    }
    
    int main()
    {
        //freopen("test.in","r",stdin);
        while(~scanf("%d%d",&n,&m)){
            int u,v;
            memset(head,-1,sizeof(head));
            edge_cnt = 0;
            FOR(i,1,m+1){
                scanf("%d%d",&u,&v);
                AddEdge(u,v,i);
                AddEdge(v,u,i);
            }
            while(!s.empty())   s.pop();
            dfs_clock = 0;
            memset(dfn,0,sizeof(dfn));
            cnt = 0;
            dfs(1,-1);
            if(!s.empty())  cnt++;
            int  minx = INF;
            while(!s.empty()){
                int tem = s.top(); s.pop();
                pos[tem] = cnt;
                minx = min(minx,tem);
            }
            ans[cnt] = minx;
            printf("%d
    ",cnt);
            printf("%d",ans[pos[1]]);
            FOR(i,2,m+1){
                printf(" %d",ans[pos[i]]);
            }
            printf("
    ");
        }
        return 0;
    }


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    递归函数及Java范例
    笔记本的硬盘坏了
    “References to generic type List should be parameterized”
    配置管理软件(configuration management software)介绍
    WinCE文件目录定制及内存调整
    使用Silverlight for Embedded开发绚丽的界面(3)
    wince国际化语言支持
    Eclipse IDE for Java EE Developers 与Eclipse Classic 区别
    WinCE Heartbeat Message的实现
    使用Silverlight for Embedded开发绚丽的界面(2)
  • 原文地址:https://www.cnblogs.com/hqwhqwhq/p/4811897.html
Copyright © 2011-2022 走看看