Skip to content

Commit bccc8b0

Browse files
committed
[AcWing Base course] Graph, BiPartGraph
1 parent f4e5b58 commit bccc8b0

File tree

4 files changed

+316
-0
lines changed

4 files changed

+316
-0
lines changed

Diff for: Graph/BiPartGraph/AW860_BiPartGraph.cpp

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
一个图是二分图 当且仅当 图中不含奇数环
3+
4+
输入样例:
5+
4 4
6+
1 3
7+
1 4
8+
2 3
9+
2 4
10+
输出样例:
11+
Yes
12+
*/
13+
14+
#include <bits/stdc++.h>
15+
using namespace std;
16+
const int N = 1e5 + 10, M = 2e5 + 10;
17+
18+
int n, m;
19+
int firstEdge[N], endPoint[M], nextEdge[M], idx;
20+
21+
int color[N];
22+
23+
void add(int u, int v) {
24+
endPoint[idx] = v;
25+
nextEdge[idx] = firstEdge[u];
26+
firstEdge[u] = idx;
27+
idx++;
28+
}
29+
/* c: 1 or 2 */
30+
bool dfs(int u, int c) {
31+
color[u] = c;
32+
for(int edge = firstEdge[u]; edge != -1; edge = nextEdge[edge]) {
33+
int end = endPoint[edge];
34+
/* not colored */
35+
if(color[end] == 0) {
36+
if(not dfs(end, 3 - c)) {
37+
return false;
38+
}
39+
} else if(color[end] == c) {
40+
return false;
41+
}
42+
}
43+
return true;
44+
}
45+
46+
int main() {
47+
cin >> n >> m;
48+
memset(firstEdge, -1, sizeof(firstEdge));
49+
while(m--) {
50+
int a, b;
51+
cin >> a >> b;
52+
add(a, b), add(b, a);
53+
}
54+
bool flag = true;
55+
for(int i = 1; i <= n; i++) {
56+
if(color[i] == 0) {
57+
if(not dfs(i, 1)) {
58+
flag = false;
59+
break;
60+
}
61+
}
62+
}
63+
if(flag) {
64+
cout << "Yes" << endl;
65+
} else {
66+
cout << "No" << endl;
67+
}
68+
return 0;
69+
}

Diff for: Graph/BiPartGraph/AW860_BiPartGraph_yxc.cpp

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
AcWing
3+
860. 染色法判定二分图
4+
1e5
5+
6+
输入样例:
7+
4 4
8+
1 3
9+
1 4
10+
2 3
11+
2 4
12+
输出样例:
13+
Yes
14+
15+
作者:yxc
16+
链接:https://www.acwing.com/activity/content/code/content/48778/
17+
来源:AcWing
18+
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
19+
20+
https://www.acwing.com/solution/content/105874/
21+
22+
什么叫二分图
23+
24+
有两顶点集且图中每条边的的两个顶点分别位于两个顶点集中,每个顶点集中没有边直接相连接!
25+
26+
说人话的定义:
27+
图中点通过移动能分成左右两部分,左侧的点只和右侧的点相连,右侧的点只和左侧的点相连。
28+
*/
29+
30+
#include <cstring>
31+
#include <iostream>
32+
#include <algorithm>
33+
34+
using namespace std;
35+
36+
const int N = 100010, M = 200010;
37+
38+
int n, m;
39+
int h[N], e[M], ne[M], idx;
40+
int color[N]; // 标记每个点的颜色(0表示未染色),color[i]=0,1,...
41+
42+
void add(int a, int b) {
43+
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
44+
}
45+
46+
bool dfs(int u, int c) {
47+
color[u] = c; // 点u染c色
48+
49+
// 遍历u的所有邻接点j
50+
for (int i = h[u]; i != -1; i = ne[i]) {
51+
int j = e[i];
52+
53+
// j未染色
54+
if (!color[j]) {
55+
// 从j开始深度优先遍历图,逐个染色
56+
if (!dfs(j, 3 - c))
57+
return false;
58+
}
59+
// j已染色
60+
else if (color[j] == c)
61+
return false; // 出现奇数环导致j与i同色
62+
}
63+
64+
return true;
65+
}
66+
67+
int main() {
68+
scanf("%d%d", &n, &m);
69+
70+
// 建立邻接表
71+
memset(h, -1, sizeof h);
72+
while (m--) {
73+
int a, b;
74+
scanf("%d%d", &a, &b);
75+
add(a, b), add(b, a);
76+
}
77+
78+
// 染色法
79+
bool flag = true;
80+
// 考虑到非连通图的情况,保证遍历到每一个点
81+
for (int i = 1; i <= n; i++) {
82+
if (!color[i]) { // 若i未染色
83+
if (!dfs(i, 1)) { // 从i开始深度优先遍历图,逐个染色
84+
flag = false; // 出现矛盾,染色失败
85+
break;
86+
}
87+
}
88+
}
89+
90+
if (flag)
91+
puts("Yes");
92+
else
93+
puts("No");
94+
95+
return 0;
96+
}

Diff for: Graph/BiPartGraph/AW861_Hungarian.cpp

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
二分图的最大匹配
3+
AcWing 861. 二分图的最大匹配
4+
5+
https://www.acwing.com/solution/content/5334/
6+
7+
有点贪心的意味
8+
9+
导读:什么是最大匹配?
10+
要了解匈牙利算法必须先理解下面的概念:
11+
12+
匹配:在图论中,一个「匹配」是一个边的集合,其中任意两条边都没有公共顶点。
13+
14+
最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。
15+
16+
下面是一些补充概念:
17+
18+
完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。
19+
20+
交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路。
21+
22+
增广路:从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),
23+
则这条交替 路称为增广路(agumenting path)。
24+
25+
https://blog.csdn.net/sunny_hun/article/details/80627351
26+
*/
27+
#include <bits/stdc++.h>
28+
using namespace std;
29+
const int N = 510, M = 1e5 + 10;
30+
31+
int firstEdge[N], endPoint[M], nextEdge[M], idx;
32+
int n1, n2, m;
33+
int match[N];
34+
bool st[N]; // 防止重复匹配一个点
35+
36+
void add(int u, int v) {
37+
endPoint[idx] = v;
38+
nextEdge[idx] = firstEdge[u];
39+
firstEdge[u] = idx;
40+
idx++;
41+
}
42+
43+
bool find(int x) {
44+
/* 枚举所有对面的结点 */
45+
for(int edge = firstEdge[x]; edge != -1; edge = nextEdge[edge]) {
46+
int end = endPoint[edge];
47+
/* 如果对面的结点没有测试过 */
48+
if(not st[end]) {
49+
st[end] = true;
50+
/* if 对面的结点没有 matched,
51+
** 或者说对面的match的男生还能 match 其他女生 */
52+
if(match[end] == 0 or find(match[end])) {
53+
match[end] = x;
54+
return true;
55+
}
56+
}
57+
}
58+
return false;
59+
}
60+
61+
int main() {
62+
cin >> n1 >> n2 >> m;
63+
memset(firstEdge, -1, sizeof(firstEdge));
64+
65+
while(m--) {
66+
int a, b;
67+
cin >> a >> b;
68+
add(a, b);
69+
}
70+
int res = 0;
71+
for(int i = 1; i <= n1; i++) {
72+
memset(st, false, sizeof(st));
73+
if(find(i)) {
74+
res++;
75+
}
76+
}
77+
cout << res << endl;
78+
return 0;
79+
}
80+
/*
81+
输入样例:
82+
2 2 4
83+
1 1
84+
1 2
85+
2 1
86+
2 2
87+
输出样例:
88+
2
89+
*/

Diff for: Graph/BiPartGraph/AW861_Hungarian_yxc.cpp

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#include <iostream>
2+
#include <algorithm>
3+
#include <cstring>
4+
5+
using namespace std;
6+
7+
const int N = 510, M = 100010;
8+
9+
int n1, n2, m;
10+
// n1表示左边点的数量(男生),n2表示右边点的数量(女生),图中有m条边
11+
int h[N], e[M], ne[M], idx;
12+
// h[]邻接表的头节点,e[]存值,ne[]存下一个点的地址,idx存当前点
13+
int match[N]; // 表示右边点其对应的点,即女与男配对里的男生
14+
bool st[N]; // 防止重复匹配一个点
15+
16+
void add(int a, int b) {
17+
// 用邻接表存图
18+
e[idx] = b;
19+
ne[idx] = h[a];
20+
h[a] = idx++;
21+
}
22+
// 匈牙利算法的实现
23+
bool find(int x) {
24+
// 枚举这个男生考虑的妹子,即其邻边连接的点
25+
for(int i = h[x]; i != -1; i = ne[i]) {
26+
int j = e[i]; // 表示当前妹子的点编号
27+
if(!st[j]) {
28+
// 还没有匹配过
29+
st[j] = true;
30+
if(match[j] == 0 || find(match[j])) {
31+
// 当前妹子没有匹配到男生||与其匹配的男生有其他备胎
32+
match[j] = x; // 枚举的男生与当前妹子匹配成功
33+
return true;
34+
}
35+
}
36+
}
37+
return false; // 都匹配不成功,单身狗一个
38+
}
39+
40+
int main() {
41+
cin >> n1 >> n2 >> m;
42+
memset(h, -1, sizeof h);
43+
44+
while(m--) // 添加边
45+
{
46+
int a, b;
47+
cin >> a >> b;
48+
add(a, b);
49+
}
50+
int res = 0; // res表示当前匹配成功的数量
51+
for(int i = 1; i <= n1; i++) // 遍历所有男生n1
52+
{
53+
memset(st, false, sizeof st); // 清空要考虑的女生
54+
if(find(i))
55+
res++;
56+
// 如果男生成功匹配到一个妹子,匹配数+1
57+
}
58+
59+
cout << res << endl;
60+
61+
return 0;
62+
}

0 commit comments

Comments
 (0)