图论——染色法判定二分图
首先明确概念:
二分图:设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。
奇数环:一个图中边数为奇数的环。
染色法原理:
首先任意取出一个顶点进行染色,和该节点相邻的点有三种情况:
1.如果未染色,那么继续染色此节点(染为另一种颜色)
2.如果已染色但和当前节点颜色不同,则跳过该点
3.如果已染色并且和当前节点颜色相同,返回失败(该图不是二分图)
明确二分图、奇数环、染色法之间的关系:
如果一个图中存在奇数环,那么这个图一定不是二分图;这一点显然成立。
如果一个图中不存在奇数环,那么这个图一定是二分图:
证明:用染色法。从某个点开始逐层交叉染色,在染色过程中:
若发现有某条边的两个端点着色相同,则必定存在奇数环①,与题意相矛盾。
若没有发现,则根据染色法原理,每一条边的两端着色必然不同,那么根据二分图的定义,就可知这个图是一个二分图。
①的证明:
不妨设这条边的两个端点着色都为1,且这两点必然是由同一个源点扩展而来。那么根据染色法原理,因为这两个点的着色相同,那么从源点到这两个点所经过的边数(假设分别为x和y)的奇偶性必然相同,那么这个环的总边数为x+y+1,由数学知识得这个数必然是奇数。
证毕!
模板题链接:染色法判定二分图
代码如下:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; const int N = 100010, M = 200010; struct Edge{ int to,next; }edge[M];int cnt; int n,m; int h[N],color[N]; void add_edge(int u,int v) { edge[++cnt].to=v; edge[cnt].next=h[u]; h[u]=cnt; } bool dfs(int u,int c) { color[u]=c; for(int i=h[u]; ~ i;i=edge[i].next) { int to=edge[i].to; if(color[to]==c) { return false; } else if(!color[to]&&!dfs(to,3-c))return false; } return true; } int main() { scanf("%d%d",&n,&m); memset(h,-1,sizeof h); for(int i=1;i<=m;i++) { int a,b;scanf("%d%d",&a,&b); add_edge(a,b);add_edge(b,a); } bool flag=true; for(int i=1;i<=n;i++) { if(!color[i]) { if(!dfs(i,1)) { flag=false; break; } } } if(flag)printf("Yes\n"); else printf("No\n"); }