求点双连通分量
首先弄明白什么是点双连通分量.无向图中如果删掉一个点之后连通块数目变多,这个点叫做”割点”,删掉一条边后连通块增加则这条边为"桥".无向图dfs得到一棵搜索树,不在树上的边都认为是回向边(或者说反向边).
不存在割点的极大连通子图叫做无向图的双连通分量。由此定义,图中的桥和两端的两个点也组成了一个点双连通分量.
关键是那个dfs函数.dfn[x]表示x在dfs中被发现的时间.low[x]表示x沿着树边往下走再往上走一条反向边能够到达的点中dfn[]最小是多少
感觉我这个bcc板子比蓝书的短多了(雾)
poj2942 Knights of the Round Table
关于这个题怎么做,可以看蓝书.
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define pb(x) push_back(x)
typedef vector<int>::iterator pt;
const int maxn=1005;
int n,m;
vector<int> bcc[maxn];int bccN;
vector<int> to[maxn];
int E[maxn][maxn],eflag=0;
int dfn[maxn],low[maxn],prt[maxn],T;
int stk[maxn],top;
void dfs(int x){//这个函数是关键
low[x]=dfn[x]=++T;
for(pt i=to[x].begin();i!=to[x].end();++i){
if(*i==prt[x])continue;//恰好沿着树边往回走?不可以的
if(dfn[*i]==0){
prt[*i]=x;
stk[++top]=*i;//一个点对应一条树边,代表x到*i所连的树边
dfs(*i);//递归搜索
if(low[*i]>=dfn[x]){
bcc[++bccN].clear();
do{
bcc[bccN].pb(stk[top]);
}while(stk[top--]!=*i);
bcc[bccN].pb(x);//注意点x还要单独加到这个BCC中
}
if(low[*i]<low[x])low[x]=low[*i];//更新low[x]
}
if(dfn[*i]<low[x])low[x]=dfn[*i];//更新low[x]
}
}
int good[maxn],gflag;
int ufs[maxn],col[maxn];
int find(int x){
if(x==ufs[x])return x;
int rt=find(ufs[x]);
col[x]^=col[ufs[x]];
return ufs[x]=rt;
}
int bccbel[maxn],belT=0;
bool link(int x,int y){
int rx=find(x),ry=find(y);
if(rx!=ry){
ufs[rx]=ry;
col[rx]=col[x]^col[y]^1;
return false;
}else{
return col[x]==col[y];
}
}
bool check(int x){
++belT;
for(pt i=bcc[x].begin();i!=bcc[x].end();++i){
ufs[*i]=*i;col[*i]=0;bccbel[*i]=belT;
}
for(pt i=bcc[x].begin();i!=bcc[x].end();++i){
for(pt j=to[*i].begin();j!=to[*i].end();++j){
if(bccbel[*j]==belT){
if(link(*i,*j))return true;
}
}
}
return false;
}
int main(){
while(scanf("%d%d",&n,&m),n!=0){
for(int i=1;i<=n;++i)to[i].clear();
++eflag;
for(int i=1,a,b;i<=m;++i){
scanf("%d%d",&a,&b);
E[a][b]=E[b][a]=eflag;
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(i!=j&&E[i][j]!=eflag)to[i].pb(j);
memset(dfn,0,sizeof(dfn));
memset(prt,0,sizeof(prt));
memset(low,0,sizeof(low));
top=0;T=0;bccN=0;
for(int i=1;i<=n;++i){
if(dfn[i]==0)dfs(i);
}
++gflag;
for(int i=1;i<=bccN;++i){
if(check(i)){
for(pt j=bcc[i].begin();j!=bcc[i].end();++j){
good[*j]=gflag;
}
}
}
int ans=0;
for(int i=1;i<=n;++i){
if(good[i]!=gflag)++ans;
}
printf("%d\n",ans);
}
return 0;
}