二分的两段性:假设 x 为最优解,即、x -> 右的边可以构成二分图,若 x 向右移动,仍然可以构成二分图(二分图去掉一些边仍然是二分图,减去一些限制,更自由了),左边一定不成立,应为 x 为当前的最优解,所以若 check(mid) == true,则当前的图可以构成二分图,向左移动看是否可以构成二分图,若恰好可以构成,则为最优解。
int n; // n表示点数 int h[N], e[M], ne[M], idx; // 邻接表存储图 int color[N]; // 表示每个点的颜色,0表示未染色,1表示白色,2表示黑色 // 参数:u表示当前节点,c表示当前点的颜色 booldfs(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)) returnfalse; } elseif (color[j] == c) returnfalse; } returntrue; } boolcheck() { memset(color, 0, sizeof color);
bool flag = true; for (int i = 1; i <= n; i ++ ) if (!color[i]) if (!dfs(i, 1)) { flag = false; break; } return flag; }
boolfind(int x, int y) { for (int i = 0; i < 8; i ++ ) { int a = x + dx[i], b = y + dy[i]; if(a < 1 || a > n || b < 1 || b > m) continue; if(st[a][b] || g[a][b]) continue; st[a][b] = true; PII t = match[a][b]; if(!t.x || find(t.x, t.y)) { match[a][b] = {x, y}; returntrue; } } returnfalse; }
intmain() { cin >> n >> m >> k; for (int i = 0; i < k; i ++ ) { int a, b; cin >> a >> b; g[a][b] = true; } int res = 0; for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= m; j ++ ) { if((i + j) % 2 || g[i][j]) continue; memset(st, 0, sizeof st); if(find(i, j)) res ++; } cout << n * m - k - res << endl; return0; }
boolfind(int x) { for (int i = 1; i <= n; i ++ ) { if(!st[i] && g[x][i]) { st[i] = true; int t = match[i]; if(t == 0 || find(t)) { match[i] = x; returntrue; } } } returnfalse; }
intmain() { cin >> n >> m; while(m -- ) { int a, b; cin >> a >> b; g[a][b] = true; } for (int k = 1; k <= n; k ++ ) for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) g[i][j] |= g[i][k] & g[k][j]; int res = 0; for (int i = 1; i <= n; i ++ ) { memset(st, 0, sizeof st); if(find(i)) res ++; } cout << n - res << endl; return0; }