有一张 n*m 的棋盘,每个位置上有一颗棋子 X 或 O。若一块区域的 O 被 X 四周包围,那么这些 O 会变成 X,除了边界上的 O。
给定一张棋盘和初始状态的棋子,输出变化后的棋盘。
示例
输入: X X X X X X O O X X X X O X X X X X O X X O X O X 输出: X X X X X X X X X X X X X X X X X X O X X O X O X
思路
岛屿问题,先写个 dfs 模板
1 2 3 4 5 6 7 8 9 10 11
voiddfs(vector<vector<char> >& grid, int i, int j){ if (!isInAread(grid, i, j)) { // 判断是否越界 return; } // do something dfs(grid, i-1, j); // 上 dfs(grid, i, j+1); // 右 dfs(grid, i+1, j); // 下 dfs(grid, i, j-1); // 左 // do something }
然后,考虑要对哪些位置 dfs 以及 dfs 过程中做什么操作、判断什么条件。
解法
方法一 边查边改
直接用模板,对所有的 O 进行 dfs,去判断每一个 O 四个方向上是否都可以通往 X,若是,则将 O 改为 X。
暂时没整出来优雅的代码
代码
1 2
// FBI WARNING // TODO
时间复杂度 O(m*n)
空间复杂度 O(m*n)
方法二 先污染再治理
首先注意到,边界上的 O 是肯定不会改变的,只有内圈的才有可能改变。那么,换种思路
先污染:把所有的内圈 O 变成中间状态 W;
再治理:判断并修改中间状态 W 的最后状态。
如何判断?应该从恒定的初始位置状态出发,也就是边界上的 O。
从每个边界上的 O出发执行 dfs,将dfs过程中遇到的中间状态 W 都给改成 O (说明这个原始 O 没有被封闭);
voiddfs(vector<vector<char> >& board, int i, int j){ int m = board.size(), n = board[0].size(); // cout << i << " " <<j << endl; if (i == m || j == n || i < 0 || j < 0 || board[i][j] != 'W') { return; } board[i][j] = 'O'; dfs(board, i-1, j); dfs(board, i+1, j); dfs(board, i, j+1); dfs(board, i, j-1); }
intmain(){ int m, n; cin >> m >> n; vector<vector<char> > board(m, vector<char>(n)); for (int i=0; i<m; ++i) { for (int j=0; j<n; ++j) { cin >> board[i][j]; if (board[i][j] == 'O') { board[i][j] = 'W'; } } } cout << endl; for (int i=0; i<m; ++i) { dfs(board, i, 0); dfs(board, i, n-1); } for (int j=0; j<n; ++j) { dfs(board, 0, j); dfs(board, m-1, j); } for (int i=0; i<m; ++i) { for (int j=0; j<n; ++j) { if (board[i][j] == 'W') { board[i][j] = 'X'; } cout << board[i][j]; } cout << endl; } return0; }