染色法判定二分图
二分图染色法
即可以把所有的点划分到两个集合内,集合内部没有边存在。
一个图是二分图,当且仅当该图中不含奇数环 ——>不含奇数环,那么一定是二分图。有奇数环的话,那么就不能二分图。
判定二分图的依据:若出现一条边的两个端点是同样的颜色(即一个集合的话),那么就不能划分为二分图。
一条边的两个端点一定属于不同的集合。
一个连通块中只要有一个点颜色或集合确定了,那么该连通块中其他所有的点的颜色集合都被确定了。
染色法判定的过程:
for : i 1 - n
if i未染色
dfs(i, 1) //把i所在连通块的端点用深搜法全部确定染色
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 100010, M = 2 * N; int n, m; int h[N], ne[M], e[M], idx; int color[N]; void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx ++; } bool dfs(int u, int c) { color[u] = c; for(int i = h[u]; i != -1;i = ne[i]) { int j = e[i]; if(!color[j]){ //这里要加上一个大括号 if(!dfs(j, 3 - c)) return false; } else if(color[j] == c) return false; } return true; } int main() { memset(h, -1, sizeof h); cin>>n>>m; while(m--) { int a, b; cin>>a>>b; add(a, b), add(b, a); } bool flag = true; for(int i = 1;i <= n;i++) if(!color[i]) { if(!dfs(i, 1)) { flag = false; break; } } if(flag) puts("Yes"); else puts("No"); }
注意这里用的染色法color[N], 默认是0,如果!color[i]说明未染色,那么就要dfs(i, 1)进行染色,用邻接表的方式确定下一个该点有边连接的另外一个点,继续dfs(e[i], 3 - c)如果递归返回false,那么不能染,如果该点染色的color[j] == color[u] = c的话,那么也失败了。
注意这里color[i]最好不要用0 和 1, 因为判断有没有染色用的就是!color[i],用0 的话会造成染了和未染混淆。