您的位置:首页 > 其它

sth. about tarjan

2016-09-01 21:11 190 查看
感觉进入了 一个 深坑!

脑子不好使 决定 写一写。。

主要决定 写一写双联通分量

先介绍:

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 写法 博大精深啊!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: