zoj 1654 Place the Robots 最大二分匹配
转换成最大匹配。
每个横向的'o’和'#’块(必须包含'o’)作为X集合一个顶点,每个纵向的'o’和'#’块(必须包含'o’)作为Y集合一个顶点
当横向块和纵向块的交点的'o’时,二分图该两个顶点有边相连接。
这题因为下标不小心打错了,调了很久才ac,纳闷。
#include <iostream> #include <cstring> using namespace std; const int N = 55; const int MAX = N*N; struct hori_block { int row; int col_left, col_right; }; struct ver_block { int col; int row_up, row_dow; }; hori_block X[MAX]; ver_block Y[MAX]; char map[N][N]; bool maze[MAX][MAX]; int match[MAX]; bool isvisit[MAX]; int row, col; int cnt_x, cnt_y; void build_graph() { cnt_x = 0; cnt_y = 0; for (int i = 0; i < row; i++) for (int j = 0; j < col; j++) { if (map[i][j] == 'o') { X[cnt_x].row = i; for (int k = j; k >= 0; k--) if (map[i][k] != '#') X[cnt_x].col_left = k; else break; while (j < col && map[i][j] != '#') { X[cnt_x].col_right = j; j++; } cnt_x++; } } for (int j = 0; j < col; j++) for (int i = 0; i < row; i++) { if (map[i][j] == 'o') { Y[cnt_y].col = j; for (int k = i; k >= 0; k--) if (map[k][j] != '#') Y[cnt_y].row_up = k; else break; while (i < row && map[i][j] != '#') { Y[cnt_y].row_dow = i; i++; } cnt_y++; } } memset(maze, false, sizeof(maze)); for (int i = 0; i < cnt_x; i++) for (int j = 0; j < cnt_y; j++) if (X[i].row >= Y[j].row_up && X[i].row <= Y[j].row_dow && Y[j].col >= X[i].col_left && Y[j].col <= X[i].col_right && map[ X[i].row ][ Y[j].col ] == 'o') maze[i][j] = true; } bool find(int u) { for (int i = 0; i < cnt_y; i++) { if (maze[u][i] && !isvisit[i]) { isvisit[i] = true; if (match[i] == -1 || find(match[i])) { match[i] = u; return true; } } } return false; } int max_match() { int ans = 0; memset(match, -1, sizeof(match)); for (int i = 0; i < cnt_x; i++) { memset(isvisit, false, sizeof(isvisit)); if (find(i)) ans++; } return ans; } int main() { int cases; cin >> cases; for (int k = 1; k <= cases; k++) { cin >> row >> col; for (int i = 0; i < row; i++) for (int j = 0; j < col; j++) cin >> map[i][j]; build_graph(); cout << "Case :" << k << endl; cout << max_match() << endl; } return 0; }