sth. about tarjan

感觉进入了 一个 深坑!
脑子不好使 决定 写一写。。

主要决定 写一写双联通分量
先介绍:
1.割点: 如果一个点去掉 图就不再联通 则这个点 为 割点
2.点双联通: 没有 割点 的图
3.边双连通:没有 割边 的图

那 总结一下 所有 的 tajan吧
1.强连通分量:

void tarjan(int x)
{
    low[x]=dfn[x]=++time;
    instack[x]=1;
    stack[++top]=x;
    for(int i=first[x];i!=-1;i=e[i].nxt)
    {
        int v=e[i].t;
        if(!dfn[v])
        {
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(instack[v])
        {
            low[x]=min(low[x],dfn[v]);
        }
    }
    if(low[x] == dfn[x])
    {
        ++index;
        while(1)
        {
            int t=stack[top--];
            instack[t]=0;
            belong[t]=index;
            if(t ==x) break;
         } 
    }
}

2.边双【边双和强连通分量差不了多少 】

唯一的差距大概就是 要统计 一下 编号 来判断 块 
当然 无向边  是要判一下 平行边的
void tarjan(int x,int f)
{
    low[x]=dfn[x]=++time;
    instack[x]=1;
    stack[++top]=x;
    for(int i=first[x];i!=-1;i=e[i].nxt)
    {
        int v=e[i].t;
        if(!dfn[v])
        {
            tarjan(v,x);
            low[x]=min(low[x],low[v]);
        }
        else if(v!=f && instack[v])
        {
            low[x]=min(low[x],dfn[v]);
        }
    }
    if(low[x] == dfn[x])
    {
        ++index;
        while(1)
        {
            int t=stack[top--];
            instack[t]=0;
            belong[t]=index;
            if(t ==x) break;
         } 
    }
}
...
    for(int i=1;i<=n;i++)
    {
        for(int j=first[i];j!=-1;j=e[j].nxt)
        {
            int v=e[j].t;
            if(belong[i]!=belong[v])
            {
                deg[belong[i]]++;
            }
        }
    }

3.割点
割点 主要就是:low[f]>=dfn[v];
如果就是根节点 那么 根节点 的子树 大于1
别的点的话 这样 的点 大于等于 1
【其中去掉后 联通块的数量 也要分情况
如果 是 根节点 就是 满足条件的数量
不是根节点就是加一

直接给 poj 1523 的代码

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
//by mars_ch
int n;
struct data
{
    int f,t;
    int nxt;
}e[1005*1005];
int first[1005];
int dfn[1005],low[1005],sson[1005],instack[1005],vis[1005];
int tot,time,root,top,cnt; 
void add(int a,int b)
{
    e[++tot].f=a;
    e[tot].t=b;
    e[tot].nxt=first[a];
    first[a]=tot;
}
void tarjan(int x)
{
    low[x]=dfn[x]=++time;
    instack[x]=1;
    for(int i=first[x];i!=-1;i=e[i].nxt)
    {
        int t=e[i].t;
        if(!dfn[t])
        {
            tarjan(t);
            low[x]=min(low[x],low[t]);
            if(low[t]>=dfn[x])
            {
                sson[x]++;
            }
        }
        else 
        {
            low[x]=min(low[x],dfn[t]);
        }
    }
}
int main()
{
    int a,b,cases=0;
    while(scanf("%d",&a) && a!=0)
    {  
        memset(first,-1,sizeof(first));
        memset(sson,0,sizeof(sson));
        memset(vis,0,sizeof(vis));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        time=0,top=0,tot=0,root=0,cnt=0;
        bool flag=false;
        scanf("%d",&b);
        if(!vis[a]) ++cnt,vis[a]=1;
        if(!vis[b]) ++cnt,vis[b]=1;  
        add(a,b);
        add(b,a);
        while(scanf("%d",&a) && a)
        {  
            scanf("%d",&b); 
            if(!vis[a]) ++cnt,vis[a]=1;
            if(!vis[b]) ++cnt,vis[b]=1;  
            add(a,b);
            add(b,a); 
        }  
        tarjan(1);
        printf("Network #%d\n",++cases);
        if(sson[1]>1) flag=true,printf("  SPF node 1 leaves %d subnets\n",sson[1]);
        for(int i=2;i<=cnt;i++)
            {
                //printf("%d %d\n",i,sson[i]);
                if(sson[i])
                {
                    printf("  SPF node %d leaves %d subnets\n",i,sson[i]+1);
                    flag=1;
                }
            }
        if(!flag) printf("  No SPF nodes\n");
        puts("");
    }
    return 0;
}

4.割边
这个就是 在割点的情况上 存一个边

void tarjan(int u,int f)
{
    int s=0;
    low[u]=dfn[u]=++time;
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(!(low[v]>dfn[u]))
            {
                merge(v,u);
            }
            else
            {
                br[++brn][0]=u;
                br[++brn][1]=v;
            }
        }
        else if(v!=f)
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
}

5.点双
研究结果是 在栈中存 边

但是还没有写过 题。

暂时 先这么着吧
tarjan 写法 博大精深啊!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值