二分图判定:
利用广度优先搜索可以判断一个图是否为二分图。起点s显然可以随意定色,每次考虑一条边(u,v)时显然u所在集合已定,因此当v为白色时把它放到不包含u的那个集合,而当v为灰色或黑色时(此时v所在集合已经确定)检查v和u是否在同一个集合。如果是,则该图不是二分图,失败退出。如果是没有失败,则算法实际上已经构造出了这两个集合。在忽略s所在集合的情况下,这个集合的分划是唯一的(算法步骤中的每一步都是强制的)。
1
2
bool Is_BipartiteGraph(int n,int id[] /**//* 二分节点集 */ )
{
3
int k,cnt=0;
4
enum
{Gray,Black,White} color[N];
5
queue<int> _que;
6
for(int i=0;i<n;i++) color[i]=White;
7
_que.push(0); color[0]=Black; id[0]=cnt;
8
while(!_que.empty())
{
9
k=_que.front(); _que.pop();
10
for(int i=0;i<n;i++)
11
if( g[k][i] )
{
12
if( Gray == color[i] | Black == color[i] )
{
13
if( id[i] == id[k] ) return false;
14
}
15
else
{
16
id[i]=1-id[k];
17
color[i]=Gray;
18
_que.push(i);
19
}
20
}
21
color[k]=Black;
22
}
23
return true;
24
}
Time_stamp-DFS+边分类算法:
把分类规则落实到DFS中,只需在考虑边(u,v)时检查v的颜色:
v是白色,(u,v)是 树边 Tree edge
v是灰色,(u,v)是 后向边 Back edge
v是黑色,继续判定。若find[u]<find[v]说明v是u的后代,因此它是前向边Forward edge,否则为交叉边Cross edge。
1
enum
{ Tree,Back,Forward,Cross } id[N][N];
2
enum
{ Black,White,Gray } color[N]=
{White};
3
int finish[N],find[N];
4
int time=0;
5
void DFS(int s)
{
6
color[s]=Gray; // 开始扩展
7
find[s]=++time;
8
for(int i=0;i<n;i++)
9
if(g[s][i])
{
10
switch (color[i])
{
11
case White:
{
12
id[s][i]=Tree;
13
DFS(i);
14
break;
15
}
16
case Gray:
{
17
id[s][i]=Back;
18
break;
19
}
20
case Black:
{
21
if(find[s]<find[i]) id[s][i]=Forward;
22
else id[s][i]=Cross;
23
break;
24
}
25
}
26
}
27
color[s]=Black; //事件结束
28
finish[s]=++time;
29
}