首先弄明白什么是點雙連通分量.無向圖中如果刪掉一個點之后連通塊數目變多,這個點叫做”割點”,刪掉一條邊后連通塊增加則這條邊為"橋".無向圖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;
}