二分图判定:
利用广度优先搜索可以判断一个图是否为二分图。起点s显然可以随意定色,每次考虑一条边(u,v)时显然u所在集合已定,因此当v为白色时把它放到不包含u的那个集合,而当v为灰色或黑色时(此时v所在集合已经确定)检查v和u是否在同一个集合。如果是,则该图不是二分图,失败退出。如果是没有失败,则算法实际上已经构造出了这两个集合。在忽略s所在集合的情况下,这个集合的分划是唯一的(算法步骤中的每一步都是强制的)。
1
2bool 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。
1enum{ Tree,Back,Forward,Cross } id[N][N];
2enum{ Black,White,Gray } color[N]={White};
3int finish[N],find[N];
4int time=0;
5void 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}