无向图的割点和桥

割点:

void tarjan(int u){
    dfn[u]=low[u]=++cnt;
    int flag=0;
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]){//就一个割点判断法则没必要解释什么了吧?
                flag++;
                if(u!=rt||flag>1)cut[u]=1;
            }
        }else low[u]=min(low[u],dfn[v]);
    }
}
View Code

桥:

void tarjan(int u,int in_edge){//in_edge表示递归进入每个节点的边的编号 
    dfn[u]=low[u]=++cnt;
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(!dfn[v]){
            tarjan(v,i);
            low[u]=min(low[u],low[v]);//在搜索树上的边
            if(low[y]>dfn[u])//桥判定法则
                bridge[i]=bridge[i^1]=1;//这条边和它的反向边都是桥
        }else if(i!=(in_edge^1))///实际上也就是不要走到父亲去 
            low[u]=min(low[u],dfn[v]);//不在搜索树上的边
    }
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        addedge(x,y);addedge(y,x);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])tarjan(i,0);
    for(int i=0;i<tot;i+=2)
        if(bridge[i])
            printf("%d %d
",e[i^1].v,e[i].v);//输出桥两边的点
            //printf("%d %d
",to(i^1),to(i));//输出桥两边的点
}
View Code

poj 1144

http://poj.org/problem?id=1144

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
int mi(int x,int y){
    return x<y?x:y;
}
inline int read(){
    int sum=0,x=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            x=0;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
    }
    //cout<<"~~"<<endl;
    return x?sum:-sum;
}
inline void write(int x){
    if(x<0)
        putchar('-'),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
}
const int M=101;
int dfn[M],low[M],head[M],cut[M],tot,cnt,son;
struct node{
    int v,nextt;
}e[M*M];
void addedge(int u,int v){
    e[tot].v=v;
    e[tot].nextt=head[u];
    head[u]=tot++;
}

void tarjan(int u){
    dfn[u]=low[u]=++cnt;
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(!dfn[v]){
            tarjan(v);
            if(u==1)
                son++;
            else{
                low[u]=mi(low[u],low[v]);
                if(dfn[u]<=low[v])
                    cut[u]=1;
            }
        }
        else
            low[u]=mi(low[u],dfn[v]);
    }
}

int n;
void init(){
    for(int i=0;i<=n;i++)
        dfn[i]=low[i]=cut[i]=0,head[i]=-1;
    son=0,tot=0,cnt=0;
}
int main(){
    while(~scanf("%d",&n)&&n){
        init();
        int u;
        while(scanf("%d",&u)&&u){
            while(getchar()!='
'){
                int v;
                scanf("%d",&v);
                addedge(u,v);
                addedge(v,u);
            }
        }
        tarjan(1);
        int ans;
        if(son>=2)
            ans=1;
        else
            ans=0;
        for(int i=1;i<=n;i++)
            if(cut[i])
                ans++;
        //cout<<ans<<endl;
        write(ans);
        putchar('
');
    }
    return 0;
}
View Code

题:http://poj.org/problem?id=1523

题意:问割点包含的点的个数

#include<bits/stdc++.h>
using namespace std;
const int M=1e3+3;
int head[M],dfn[M],cut[M],low[M],n,tot,cnt,rt;
struct node{
    int v,nextt;
}e[M*10];
void addedge(int u,int v){
    e[tot].v=v;
    e[tot].nextt=head[u];
    head[u]=tot++;
}
void tarjan(int u){//cout<<"!!"<<endl;
    dfn[u]=low[u]=++cnt;
    int flag=0;
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]){
                flag++;
                if(u!=rt||flag>1)
                    cut[u]++;
            }
        }
        else
            low[u]=min(low[u],dfn[v]);
    }
}
void init(){
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(cut,0,sizeof(cut));
    n=0,tot=0,cnt=0;
}
int main(){
    int u,v,sign=1;
    while(~scanf("%d",&u)&&u){
        init();
        n=max(n,u);
        while(scanf("%d",&v)){
            n=max(n,v);
            addedge(u,v);
            addedge(v,u);
            scanf("%d",&u);
            n=max(n,u);
            if(!u)
                break;
        }
        
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                rt=i,tarjan(i);
        printf("Network #%d
",sign++);
        int flag=0;
        for(int i=1;i<=n;i++){
            if(cut[i]){
                flag=1;
                printf("  SPF node %d leaves %d subnets
",i,1+cut[i]);
            }
        }
        if(!flag)
            printf("  No SPF nodes
");
        putchar('
');
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/starve/p/10956558.html