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;
    }


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

  • 相关阅读:
    K-means Algorithm
    Naive Bayes Algorithm
    Generalized Linear Models
    Support Vector Machine
    wordpress迁移
    Gaussian Discriminant Analysis
    Locally Weighted Regression
    Matlab绘图高级部分
    Supervised Learning-Regression
    html 字符串互转DOM
  • 原文地址:https://www.cnblogs.com/hqwhqwhq/p/4811897.html
Copyright © 2011-2022 走看看