• 【专题】图的连通性问题无向图的点连通性的求解及应用


    1.求割点:

    (1).朴素的方法:n^3

    (2).Tarjan求割点:n^2

     顶点u是割点的充要条件:

    1.如果顶点u是深度优先搜索生成树的根,则u至少有两个子女.

    2.如果u不是生成树的根,则它至少有一个子女w,从w出发,不可能通过w、w的子孙,以及一条回边组成的路径到达u的祖先.

    (low[w]>=dfn[u]).

    去掉割点,将原来的连通图分成了几个连通分量?

    1.如果割点u是根结点,则有几个子女,就分成了几个连通分量.

    2.如果割点u不是根结点,则有d个子女w,使得low[w]>=dfn[u],则去掉该结点,分成了d+1个连通分量。

    下面是一段求割点的代码:

    View Code
    /*Source Code
    Problem: 1523  User: HEU_daoguang
    Memory: 4628K  Time: 16MS
    Language: G++  Result: Accepted
    Source Code*/
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    using namespace std;
    #define min(a,b) ((a)>(b)?(b):(a));
    int Edge[1001][1001];
    int visited[1001];
    int nodes;
    int tmpdfn;
    int dfn[1001];
    int low[1001];
    int son;
    int subnets[1001];
    void init()
    {
        low[1]=dfn[1]=1;
        tmpdfn=1;
        son=0;
        memset(visited,0,sizeof(visited));
        visited[1]=1;
        memset(subnets,0,sizeof(subnets));
    }
    void dfs(int u)
    {
        for(int v=1;v<=nodes;v++)
        {
            if(Edge[u][v])
            {
                if(!visited[v])
                {
                    visited[v]=1;
                    tmpdfn++;
                    dfn[v]=low[v]=tmpdfn;
                    dfs(v);
                    low[u]=min(low[u],low[v]);
                    if(low[v]>=dfn[u])
                    {
                        if(u!=1)
                            subnets[u]++;
                        if(u==1) son++;
                    }
                }
                else
                {
                    low[u]=min(low[u],dfn[v]);
                }
            }
        }
    }
    
    int main()
    {
        int i;
        int u,v;
        int find;
        int number=1;
        while(1)
        {
            scanf("%d",&u);
            if(u==0)
            {
                break;
            }
            memset(Edge,0,sizeof(Edge));
            nodes=0;
            scanf("%d",&v);
            if(u>nodes) nodes=v;
            if(v>nodes) nodes=u;
            Edge[u][v]=Edge[u][v]=1;
            while(1)
            {
                scanf("%d",&u);
                if(u==0) break;
                scanf("%d",&v);
                if(u>nodes) nodes=u;
                if(v>nodes) nodes=v;
                Edge[u][v]=Edge[v][u]=1;
            }
    
            if(number>1) printf("\n");
            printf("Network #%d\n",number);
            number++;
            init();
            dfs(1);
            if(son>1) subnets[1]=son-1;
            find=0;
            for(i=1;i<=nodes;i++)
            {
                if(subnets[i])
                {
                    find=1;
                    printf("  SPF node %d leaves %d subnets\n",i,subnets[i]+1);
                }
            }
            if(!find) printf("  No SPF nodes\n");
        }
        return 0;
    }

     2.求双连通分量:

    双连通分量特性:无割点,删除任何一点都不会影响其他点之间的通信。

    双连通图:无割点的图.

    下面是一段求双连通分量的代码:

    View Code
    #include <string.h>
    #include <iostream>
    #include <stdio.h>
    #define min(a,b) ((a)>(b)?(b):(a))
    #define MAXN 20
    #define MAXM 40
    struct edge{
        int u,v;
    }edges[MAXM];
    int top;
    int Edge[MAXN][MAXN];
    int vis[MAXN];
    int n,m;
    int tmpdfn;
    int dfn[MAXN];
    int low[MAXN];
    void dfs(int u){
        for(int v=1;v<=n;v++){
            if(Edge[u][v]==1){
                edge t;
                t.u=u;
                t.v=v;
                edges[++top]=t;
                Edge[u][v]=Edge[v][u]=2;
                if(!vis[v]){
                    vis[v]=1;
                    tmpdfn++;
                    dfn[v]=low[v]=tmpdfn;
                    dfs(v);
                    low[u]=min(low[u],low[v]);
                    if(low[v]>=dfn[u]){
                        bool firstedge=true;
                        while(1){
                            int flag=0;
                            if(top<0) break;
                            if(firstedge) firstedge=false;
                            else printf(" ");
                            printf("%d-%d",edges[top].u,edges[top].v);
                            if((edges[top].u==u&&edges[top].v==v) || (edges[top].u==v&&edges[top].v==u)) flag=1;
                            edges[top].u=0;edges[top].v=0;
                            top--;
                            if(flag) break;
                        }
                        printf("\n");
                    }
                }
                else low[u]=min(low[u],dfn[v]);
            }
        }
    }
    int main()
    {
        int u,v;
        int number=1;
        while(scanf("%d%d",&n,&m)!=EOF){
            if(n==0 && m==0) break;
            memset(Edge,0,sizeof(Edge));
            for(int i=1;i<=m;i++){
                scanf("%d%d",&u,&v);
                Edge[u][v]=Edge[v][u]=1;
            }
            if(number>1) printf("\n");
            number++;
            low[1]=dfn[1]=1;
            tmpdfn=1;
            memset(vis,0,sizeof(vis));
            vis[1]=1;
            memset(edges,0,sizeof(edges));
            top=-1;
            dfs(1);
        }
        return 0;
    }
    /*
    input
    7 9
    1 2
    1 3
    1 6
    1 7
    2 3
    2 4
    2 5
    4 5
    6 7
    output
    5-2 4-5 2-4
    3-1 2-3 1-2
    7-1 6-7 1-6
    */

     3.求顶点连通度k(G),求最小割顶集:

    A,B为任意不相邻的两点.

    P(A,B)为A-B之间的独立轨最大条数,最少要删除P(A,B)个点才能使A,B不连通.

    求P(A,B)->构图+最大流

    结论:一个图的任意A,B两点间的P(A,B)的最小值即为该图的顶点连通度k(G),即最小割顶集.

    网络流求解:O(n^4)见代码:

    View Code
    /*Source Code
    Problem: 1966  User: HEU_daoguang
    Memory: 1056K  Time: 16MS
    Language: G++  Result: Accepted
    Source Code*/
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    using namespace std;
    #define V 300
    #define E 30000
    #define inf 0xffff
    int map[V][2];
    int flag[V][V];
    struct Edge
    {
        int u,v,c,next;
    }edge[E];
    int n,m,cnt;
    int dist[V];
    int head[V];
    int que[V];
    int sta[V];
    int s,t;
    void init(){
        cnt=0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int u,int v,int c){
        edge[cnt].u=u;edge[cnt].v=v;edge[cnt].c=c;
        edge[cnt].next=head[u];head[u]=cnt++;
        edge[cnt].u=v;edge[cnt].v=u;edge[cnt].c=0;
        edge[cnt].next=head[v];head[v]=cnt++;
    }
    
    int dinic(int s,int t){
        int ans=0;
        while(true){
            int left,right,u,v;
            memset(dist,-1,sizeof(dist));
            left=right=0;
            que[right++]=s;
            dist[s]=0;
    
            while(left<right){
                u=que[left++];
                for(int k=head[u];k!=-1;k=edge[k].next){
                    u=edge[k].u;
                    v=edge[k].v;
                    if(edge[k].c > 0 && dist[v]==-1){
                        dist[v]=dist[u]+1;
                        que[right++]=v;
                        if(v==t){
                            left=right;
                            break;
                        }
                    }
                }
            }
    
            if(dist[t]==-1) break;
    
            int top=0;
            int now=s;
    
            while(true){
                if(now!=t){
                    int k;
                    for(k=head[now];k!=-1;k=edge[k].next){
                        if(edge[k].c>0 && dist[edge[k].v]==dist[edge[k].u]+1) break;
                    }
                    if(k!=-1){
                        sta[top++]=k;
                        now=edge[k].v;
                    }
                    else{
                        if(top==0) break;
                        dist[edge[sta[--top]].v]=-1;
                        now=edge[sta[top]].u;
                    }
                }
                else{
                    int flow=inf,ebreak;
                    for(int i=0;i<top;i++){
                        if(flow>edge[sta[i]].c){
                            flow=edge[sta[i]].c;
                            ebreak=i;
                        }
                    }
                    ans+=flow;
                    for(int i=0;i<top;i++){
                        edge[sta[i]].c-=flow;
                        edge[sta[i]^1].c+=flow;
                    }
                    now=edge[sta[ebreak]].u;
                    top=ebreak;
                }
            }
        }
        return ans;
    }
    
    void build(int x,int y,int ver,int n,int m){
        init();
        for(int i=1;i<=n;i++){
            addedge(i,i+n,1);
        }
        for(int i=0;i<m;i++){
            addedge(map[i][0]+n,map[i][1],inf);
            addedge(map[i][1]+n,map[i][0],inf);
        }
        addedge(x,x+n,inf);
        addedge(y,y+n,inf);
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(scanf("%d%d",&n,&m)!=EOF){
            int a,b;
            int ver=n*2+1;
            memset(map,0,sizeof(map));
            memset(flag,0,sizeof(flag));
            for(int i=0;i<m;i++){
                scanf(" (%d,%d)",&a,&b);
                a++,b++;
                map[i][0]=a,map[i][1]=b;
                flag[a][b]=1;
            }
            if(m==0){
                if(n==1) printf("1\n");
                else printf("0\n");
                continue;
            }
            int pre,ans=inf,sign=0;
            for(int i=1;i<=n;i++){
                for(int j=i+1;j<=n;j++){
                    if(!flag[i][j]){
                        sign=1;
                        build(i,j,ver,n,m);
                        ans=min(ans,dinic(i,j+n));
                    }
                }
            }
            if(sign){
                printf("%d\n",ans);
            }
            else{
                printf("%d\n",n);
            }
        }
        return 0;
    }

    Stoer-Wagner算法:O(n^3),见博客L:

    http://www.cnblogs.com/ylfdrib/archive/2010/08/17/1801784.html

  • 相关阅读:
    【HTML】html站标设置、网页小图标
    【idea】2020完整安装过程
    pptp,l2tp获取登录用户信息用pppd参数即可
    Postfix+Dovecot+MySQL搭建邮件服务器(续)
    Postfix+Dovecot+MySQL搭建邮件服务器
    zimage 和bzimage 有什么区别
    Linux编译内核
    8种nosql数据库对比
    core dump
    ulimit -c unlimited
  • 原文地址:https://www.cnblogs.com/markliu/p/2515422.html
Copyright © 2020-2023  润新知