学习笔记(双两通分量)
双联通分量
- 边双,对于任意两个点存在至少两条边不同的路径
- 点双,对于任意两个点存在至少两条点不同的路径
性质
- 显然如果是点双就一定是边双
求法
-
边双有很好的求法,根据定义如果此边为割边(dfn[v]>low[u])(即u点儿子v无法到达u,此边为割边),那么一定不是边双,直接将割边去掉,剩下的联通快即为边双
-
点双,同样运用到Tarjan算法,注意每次遍历一条边便将其压入栈中,如果该边为割点(low[v]>=dfn[u]),则像强连通那样一直弹边,将每条边的点标记,要注意,每个点都可能属于多个点双之中,每次覆盖成最新编号即可。一直弹到此边上一次出现即可
-
此类问题写Tarjan时因为是双向边,所以要记一下父亲,不然要死循环在里面
一道题改了一个晚上,效率低了点。说一下个人想法吧,最重要的是要注意如果没有被遍历过就Tarjan,否则还要判断如果他的儿子的dfs序在他之前却又不是他父亲,也要将这条边压入栈中。(看不懂那些压点的)
板子 poj2942
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=1e3+5;
bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
template<typename T>T read()
{
T ans=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
return ans*f;
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("2942.in","r",stdin);
freopen("2942.out","w",stdout);
#endif
}
int n,m;
bool mp[N][N];
int head[N],tt;
int bl[N],cl[N],dfn[N],low[N],iscut[N],scc,id,dfs_clock;
struct edge
{
int u,v,nex;
}e[N*N];
int l[N],q[N];
bool ok[N];
void init()
{
tt=0;dfs_clock=0;l[0]=q[0]=0;
memset(head,0,sizeof head);
memset(mp,0,sizeof mp);
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
memset(ok,0,sizeof ok);
memset(iscut,0,sizeof iscut);
memset(cl,0,sizeof cl);
memset(bl,0,sizeof bl);
}
void add(int x,int y)
{
++tt;e[tt].u=x;e[tt].v=y;e[tt].nex=head[x];head[x]=tt;
}
void input()
{
int x,y;
For(i,1,m)
{
x=read<int>();y=read<int>();
mp[x][y]=mp[y][x]=1;
}
}
void build()
{
For(i,1,n)For(j,i+1,n)
{
if(!mp[i][j])add(i,j),add(j,i);
}
}
bool dfs(int u)
{
// printf("%d\n",u);
int v;
for(register int i=head[u];i;i=e[i].nex)
{
v=e[i].v;
if(bl[v]^id)continue;
if(cl[v]==cl[u])return 0;
if(!cl[v])
{
cl[v]=3-cl[u];
if(!dfs(v))return 0;
}
}
return 1;
}
void Tarjan(int u,int fa)
{
int v,x,y,ch=0;
low[u]=dfn[u]=++dfs_clock;
for(register int i=head[u];i;i=e[i].nex)
{
v=e[i].v;
if(fa==v)continue;
if(!dfn[v])
{
l[++l[0]]=i;ch++;
Tarjan(v,u);
cmin(low[u],low[v]);
if(low[v]>=dfn[u])
{
iscut[u]=1;id++;
while(1)
{
x=e[l[l[0]]].u;y=e[l[l[0]--]].v;
//cerr<<x<<' '<<y<<endl;
if(bl[x]^id)bl[x]=id;
if(bl[y]^id)bl[y]=id;
if(x==u&&v==y)break;
}
cl[u]=1;
if(!dfs(u))
{
For(i,1,n)if(bl[i]==id)ok[i]=1;
}
cl[u]=0;q[0]=0;
}
}
else if(dfn[v]<dfn[u])
{
l[++l[0]]=i;//cerr<<1<<endl;
cmin(low[u],dfn[v]);
}
}
if(ch==1&&!fa)iscut[u]=0;
}
void work()
{
For(i,1,n)
{
if(!dfn[i])Tarjan(i,0);
}
int cnt=0;
For(i,1,n)if(!ok[i])++cnt;
printf("%d\n",cnt);
}
int main()
{
file();
while(scanf("%d%d",&n,&m))
{
if(!n&&!m)break;
init();
input();
build();
work();
}
return 0;
}