作业

tarjan算法 无向图

割点

如果在连通图G中去掉一个顶点(自然同时去掉与该顶点相关联的所有边)后,该图的连通分支数增加,则称该顶点为G的割点

割边

使连通图G的边e不在G的任何一个圈上

割点集合

在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合

割边集合

如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合

点连通度

最小割点集合中的顶点数

边连通度

最小割边集合中的边数
~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~
割点
tarjan DFS 对DFS树树根进行判断,是否>1,对于其他的点u,如果非树根的直接son,而且low[u]>=dfn[p[u]],则该点的father v=p[u]使割点。
割边
1,无重边情况,遍历发现T边(u,v)并low[v]>=dfn[u],则(u,v)是割边
2,有重边情况,标记,不能用dfn[u]更新low[v];

例题

POJ的= =!次元地狱门(其实很简单)
输入
输入会包括若干网络的描述。一个网络描述会包括若干对的整数,每行一对整数来描述节点的连接情况,先后顺序是无关的,如:1 2和2 1描述了相同的连接。所有的节点编码会从1到1000.一个单独的0行来结束连接节点的列表。一个空的网络描述结束输入。输入文档中空白的行要被忽略。

输出
对于每个输入的网络中,你需要输出存在的SPF节点的列表在文档中。
文档中第一个网络需要用“Network #1”来定义,第二个则是” Network #2”等等(如样例)。每个SPF节点,输出一行,方式如下方例子所示,列出节点的编号和当这个节点失效时完全连通的子网络的个数。如果网络中没有SPF节点,输出“NO SPF nodes“即可。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这题的难点其实并不是无向图系列,而是输入方式= =,其他的只要套模板就能过= =
输入用while(),就像这样:

int t=9999;
while(t!=0){
     int i=0;
     P++;
    for(i=0;i<2;i++){
         scanf("%d",&m);
        if(m==0){
            t=0;
            break;
        }
        if(i==0){
            n=m;
        }
    }
    addedge(n,m);

其实可以更简单= =,不过我不说~
完整代码如下

#include<stdio.h>
#include<string.h>
struct node{
    int to;
    int next;
} p[1005*1005];
int dfn[1005],low[1005];
int vis[1005];
int cut[1005],head[1005];
int n,e,idex;
int root,root_son;
int max(int a,int b){
    return a<b?b:a;
}
void add(int u,int v){
    p[e].to=v;
    p[e].next=head[u];
    head[u]=e++;
}
void findCut(int u){
    dfn[u]=low[u]=idex++;
    for(int i=head[u]; i!=-1; i=p[i].next){
        int v=p[i].to;
        if(!dfn[v]){
            findCut(v);
            if(u==root)
                root_son++;
            else{
                if(low[v]<low[u])
                    low[u]=low[v];
                if(low[v]>=dfn[u])
                    cut[u]=1;
            }
        }
        else if(low[u]>dfn[v])
            low[u]=dfn[v];
    }
}
void dfs(int s){
    vis[s]=1;
    for(int i=head[s]; i!=-1; i=p[i].next){
        int v=p[i].to;
        if(!vis[v]){
            vis[v]=1;
            dfs(v);
        }
    }
}
int main(){
    int u,v,t=0;
    while(scanf("%d",&u)&&u){
        t++;
        n=-1;
        e=0;
        idex=1;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(vis,0,sizeof(vis));
        memset(cut,0,sizeof(cut));
        memset(head,-1,sizeof(head));
        n=max(n,u);
        scanf("%d",&v);
        n=max(n,v);
        add(u,v);
        add(v,u);
        while(scanf("%d",&u)&&u){
            n=max(n,u);
            scanf("%d",&v);
            n=max(n,v);
            add(u,v);
            add(v,u);
        }
        root=1;
        int flag=0;
        root_son=0;
        findCut(root);
        if(root_son>1)
            cut[root]=1;
        printf("Network #%d\n",t);
        for(int i=1; i<=n; i++){
            if(cut[i]){
                flag=1;
                memset(vis,0,sizeof(vis));
                vis[i]=1;
                int son=0;
                for(int j=head[i]; j!=-1; j=p[j].next){
                    if(!vis[p[j].to])
    {
                        dfs(p[j].to);
                        son++;
                    }
                }
                printf("  SPF node %d leaves %d subnets\n",i,son);
            }
        }
        if(!flag)
            printf("  No SPF nodes\n");
        printf("\n");
    }
    return 0;
}

坑爹的文本编辑啊,输了好久的都不见了,就剩这破代码了。。哎。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值