总体概念
染色法
基本思路步骤
- 将所有的边及其相接的边用邻接表存储起来;
- 遍历所有的点,找到未上色的点;
- 用BFS将该点及其相接的点迭代上色;
- 在上述染色步骤中,如果相邻点的颜色相同则无法形成二分图;
题目
题解
原链接:https://www.acwing.com/solution/content/105874/
代码实现
#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N = 100010 * 2;//因为是无向图,所以每两个点之间的边要存储两次
int e[N], ne[N], idx;//邻接表存储图
int h[N];
int color[N];//保存各个点的颜色
int n, m;//点和边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;//u的点成 c 染色//遍历和 u 相邻的点for(int i = h[u]; i!= -1; i = ne[i]){int j = e[i]; if(!color[j])//相邻的点没有颜色,则递归处理这个相邻点{if(!dfs(b, 3 - c)) return false;//(3 - 1 = 2, 如果 u 的颜色是2,则和 u 相邻的染成 1)//(3 - 2 = 1, 如果 u 的颜色是1,则和 u 相邻的染成 2)}else(color[j] == c)//如果已经染色,判断颜色是否为c{ return false;//如果是,说明冲突,返回 }}return true;
}int main()
{memset(h, -1, sizeof h);//初始化邻接表cin >> n >> m;for(int i = 1; i <= m; i ++)//读入边{int a, b;scanf("%d%d", &a, &b);add(a, b), add(b, a);}for(int i = 1; i <= n; i ++)//遍历点{if(!color[i])//如果没染色{if(!dfs(i, 1))//染色该点,并递归处理和它相邻的点{cout << "No" << endl;//出现矛盾,输出NO return 0;}}}cout << "Yes" << endl;//全部染色完成,没有矛盾,输出YESreturn 0;
}作者:Hasity
链接:https://www.acwing.com/solution/content/105874/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
匈牙利算法
基本思路步骤
- 邻接表存储边;
- 遍历左侧的点,接着遍历与其相连的在右侧点(二分图点被划分为左右两侧);
- 找到未连过其他点的点与其相连;
- 如果该点已经连接,尝试让连接这个点的左侧的点重新连接其他点;
题目
具体题解
原链接:https://www.acwing.com/solution/content/179030/
代码实现
#include<iostream>
#include<algorithm>
#include<cstring>using namespace std;const int N = 510, M = 1e5 + 10;int h[N], e[M], ne[M], idx;//邻接表储存边
int match[N];//match[i] = j表示与点i相连的点是j;是记录整个过程配对情况的数组;
bool st[N];//遍历到左侧一个点时,判断右侧的点是否被该点访问过了;是记录一次循环的访问情况的数组;
int n1, n2, m;
int res;//结果集void add(int a, int b)
{e[idx] = b;ne[idx] = h[a];h[a] = idx ++ ;
}bool find(int x)
{for(int i = h[x];i != -1;i = ne[i])//遍历与点x相连的点{int j = e[i];if(!st[j])//如果没有被x访问过{st[j] = true;//将其标记为true,防止重复访问;if(match[j] == 0 || find(match[j]))//如果该点没有与其他点配对过 或者 与该点配对的点能找到其他的点与其配对;{match[j] = x;return true;}}}return false;
}int main()
{cin >> n1 >> n2 >> m;memset(h, -1, sizeof h);int a, b;while(m -- ){scanf("%d%d", &a, &b);add(a, b);}for(int i = 1;i <= n1;i ++ ){memset(st, false, sizeof st);//每次访问右侧的点时,需将st全赋值为false防止被上次循环的find影响本次find的访问;if(find(i)){res ++ ;}}cout << res;return 0;
}