题意简述
给定多个连通无向图,判断这些图是不是二分图。
Step 1 建图
$2\le n\le 199$,邻接矩阵和邻接表大家都随意,根据自己的习惯来。我这里用的是 vector
实现邻接表。
另外,因为结点的编号是从 $0\sim n-1$,我不太习惯,于是在建图的时候就擅自每个结点的编号都 $+1$,把编号变成了 $1\sim n$。
1 | for(int i=1;i<=m;i++){ |
Step 2 发出开始染色的指令
(没错我在凑字数)
Tips:以下内容都把结点编号当成 $1\sim n$。
因为是连通图,所以我们从 $1$ 结点开始染色。
我们定义一个 $a$ 数组,$a_i$ 代表 $i$ 结点的颜色:$0$ 代表还没有染色,$1$ 和 $2$ 代表两种不同的颜色。$1$ 号结点随便染一个颜色。
函数里可以传一个参数(遍历到的结点编号),也可以传两个参数(遍历到的结点编号和这个结点染的颜色)。我传的是两个参数。
主函数的执行异常简单,用三目运算符可以压缩为一行:
1 | printf("%s",dfs(1,1)?"BICOLORABLE\n":"NOT BICOLORABLE\n"); |
Step 3 染色
染色我们采用 dfs 来执行。其实 bfs 也可以实现,但是显然 dfs 码量比 bfs 少亿丶丶,而且 bfs 要开结构体队列,内存更大,所以我们就使用 dfs 了。
dfs 的思路和遍历图差不多。因为只有两个颜色,所以定了 $1$ 结点的颜色后,染色的方案是唯一的。我们先找到给定点的所有直接后继,然后一个一个看:
如果它的某个直接后继与它要求染的颜色相同,这个图就不是二分图,直接
return false
即可。如果它的某个直接后继和他要求染的颜色不同,那么直!接!跳!过!
如果它的某个直接后继没有染色,那么就给这个直接后继染上与它不同的颜色,接着继续遍历这个刚被染色的直接后继的直接后继。如果此直接后继后面染色不成功,说明这个图不是二分图(因为方案唯一!),直接
return false
。
如果遍历完了,就 return true
。
1 | int f(int x){return (x==1)?2:1;} //取相反颜色 |
Step 4 其它
一定要初始化!一定要初始化!一定要初始化!
要初始化的是图和记录染色的数组。
1 | memset(map1,0,sizeof(map1)); //vector可以直接这么初始化 |
另外这是邻接表的检查代码:
1 | for(int i=1;i<=n;i++){ |
Code
最后双手献上 AC 代码:
1 |
|
提交记录:Link(没错我 UVA 登上了)
这个人是个不可爱的 BUG 制造机,不过 TA 还是很喜欢瞎搞。
祝您拥有愉快的一天~