标签:ios 色值 color const bfs 操作 node lib for
标签:二分图染色
这题是真的难想……知道是二分图染色就明白了,虽然之前没学好。
题面表面说是一张图,实际上……嗯,很多连通子图。
思路
建图\(\large \Rightarrow\)枚举点\(\large \Rightarrow\)广搜染色\(\large \Rightarrow\)判定合法不合法\(\large \Rightarrow\)用更小的染色值更新答案
建图
基本操作,前向星
枚举点
因为是多个连通子图构成的,需要枚举每一个点进行判定,如果这个点之前被染过色了就不需要理它了。
广搜染色&判定合不合法&更小的值更新答案
每次广搜都先将初始点染成1,向外周扩展一步,就染成颜色2,换色可以用取模来实现。
注意不要拿染色来当标记……我估计是没处理好吧,用染色当标记广搜挂掉了,所以就多开了一个vis
数组来标记一下入队后出队的元素,如果中途发现我们找到了一个染过色的点,如果这个点没出过队,而且还和队头的点的颜色一样,很明显,我们没有办法做到题目要求,因为两点颜色相同就说明:我们要么两个点都放河蟹要么两个点都不放——两个都是不合法的。
至于这个答案是不是最小呢?只要合法,我们就只需要选择黑色和白色中数量比较小的那一个就好了。
代码
//by Saber Alter Official
//Erishikigal & Ishtar
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <queue>
//标签:广搜染色
typedef long long ll;
typedef unsigned long long ull;
const int N = 10015, M = 100015;
struct node {
int next, to;
}edge[M << 1];
int head[N], cnt;
inline void add_edge(int u, int v) {
edge[++cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt;
}
int n, m, ans;
bool Cant, vis[N];
int color[N], sum[5];
inline void BFS(int S) {
std::queue<int> Que;
Que.push(S);
while(!Que.empty()) {
int u = Que.front();
Que.pop();
vis[u] = true;
for(int i = head[u];i;i = edge[i].next) {
int v = edge[i].to;
if(vis[v]) continue;
if(color[v] == color[u]) {
Cant = true;
break;
}
color[v] = (color[u] % 2) + 1;
sum[color[v]]++;
Que.push(v);
}
}
}
void init() {
scanf("%d %d", &n, &m);
for(int i = 1;i <= m;i++) {
int _u, _v;
scanf("%d %d", &_u, &_v);
add_edge(_u, _v);
add_edge(_v, _u);
}
}
int main() {
init();
for(int i = 1;i <= n;i++) {
if(!color[i]) {
color[i] = 1;
sum[1] = 1;
sum[2] = 0;
BFS(i);
if(Cant) {
printf("Impossible\n");
return 0;
}
ans += std::min(sum[1], sum[2]);
}
}
printf("%d\n", ans);
return 0;
}
标签:ios 色值 color const bfs 操作 node lib for
原文地址:https://www.cnblogs.com/Fructose-Ryllis/p/11835146.html