【dfs】B_CodeForce 377_A mazes(连通块问题)

一、题目描述

Pavel 喜欢网格迷宫。一个网格迷宫是一个 n × m 的长方形迷宫,其中每个单元格要么是空白的,要么是墙体。您可以从一个单元格走到另一个单元格,只要两个单元格均是空白的,且拥有一条公共的边。

Pavel 绘制了一个网格迷宫,包含的全部空白单元格形成了一个连通区域。换言之,您可以从任何一个空白的单元格,走到其它任意的空白单元格。Pavel 的迷宫如果墙体太少,他就不喜欢这个迷宫。他希望将 k 个空白的单元格转换为墙体,使得剩余的全部单元格仍然能够形成一个连通区域。请帮助他实现这个任务。

输入

第一行包含了三个整数 n, m, k (1 ≤ n, m ≤ 500, 0 ≤ k < s),其中 n 和 m 分别是迷宫的高度和宽度,k 是 Pavel 希望加入的墙体数目,并且字母 s 表示原始迷宫中的空白单元格数目。

接下来的 n 行中,每行包含 m 个字符。它们描述了原始的迷宫。如果某行中的一个字符等于 “.”,则相应的单元格为空白;如果字符等于 “#”,则单元格为墙体。

输出

打印 n 行,每行包含 m 个字符:符合 Pavel 需求的新迷宫。将已转换为墙体的原始空白单元格标识为 “X”;其它单元格必须保留为未更改状态 (也就是 “.” 和 “#”)。

数据保证:存在一个解决方案。如果有多个解决方案,可输出它们中的任意一个。

输入
3 4 2
#..#
..#.
#...
输出
#.X#
X.#.
#...

输入
5 4 5
#...
#.#.
.#..
...#
.#.#
输出
#XXX
#X#.
X#..
...#
.#.#

二、题解

方法一:dfs

  • 题目保证了一定有答案,这在一定程度上降低了难度,为什么呢?
  • 每次深搜我们都走到走不下去为止,所以,我们将整个走不下去的点设为 X,可保证图中的 . 仍是连通的。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static int N, M, k;
	static char[][] grid;
	static boolean[][] vis;
	final static int[][] dir = { {0,1},{0,-1},{1,0},{-1,0} };
	static boolean inArea(int x, int y) {
		return x >= 0 && x < N && y >= 0 && y < M;
	}
	
	static void dfs(int x, int y) {
		for (int k = 0; k < 4; k++) {
			int tx = x + dir[k][0];
			int ty = y + dir[k][1];
			if (!inArea(tx, ty) || grid[tx][ty] != '.' || vis[tx][ty]) {
				continue;
			}
			vis[tx][ty] = true;
			dfs(tx, ty);
		}
		if (k > 0) {
		    grid[x][y] = 'X';
		    k--;
		}
		    
	}
    public static void main(String[] args) throws IOException {  
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		N = sc.nextInt();
		M = sc.nextInt();
		k = sc.nextInt();
		grid = new char[N][M];
		vis = new boolean[N][M];
		for (int i = 0; i < N; i++) {
			String s = sc.next();
			for (int j = 0; j < M; j++) 
				grid[i][j] = s.charAt(j);
		}
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				if (grid[i][j] == '.')
					dfs(i, j);
			}
		}
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				System.out.print(grid[x][y]);
			}
			System.out.println();
		}
    }
}

复杂度分析

  • 时间复杂度: O ( n × m ) O(n × m) O(n×m)
  • 空间复杂度: O ( n × m ) O(n × m) O(n×m)

进阶:如果题目不保证找得到答案,你该如何处理本问题?
我的做法是:对网格进行一次 bfs,判断是否存在一个大小至少为 n*m-k 的连通块,并标记连通块,最后再次遍历网格,将没有标记的 . 当做 X 即可。


方法二:bfs

import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static int N, M, k;
	static char[][] grid;
	static boolean[][] vis;
	final static int[][] dir = { {0,1},{0,-1},{1,0},{-1,0} };
	static int cnt, sum, diff;
	static boolean inArea(int x, int y) {
		return x >= 0 && x < N && y >= 0 && y < M;
	}
	static void bfs(int x, int y) {
		Queue<int[]> q = new ArrayDeque<>();
		q.add(new int[] {x, y});
		vis[x][y] = true;
		cnt = 1;
		
		while (!q.isEmpty()) {
			int[] t = q.poll();
			for (int k = 0; k < 4; k++) {
				int tx = t[0] + dir[k][0];
				int ty = t[1] + dir[k][1];
				if (!inArea(tx, ty))
					continue;
				if (grid[tx][ty] == '.' && !vis[tx][ty]) {
			    	if (cnt == diff) {
		    	    	return;
			    	}
    				q.add(new int[]{tx, ty});
    				vis[tx][ty] = true;
				    cnt++;
				}
			}
		}
	}
    public static void main(String[] args) throws IOException {  
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		N = sc.nextInt();
		M = sc.nextInt();
		k = sc.nextInt();
		grid = new char[N][M];
		vis = new boolean[N][M];
		int sx = -1, sy = -1;
		
		for (int i = 0; i < N; i++) {
			String s = sc.next();
			for (int j = 0; j < M; j++)  {
				grid[i][j] = s.charAt(j);
				if (grid[i][j] == '.') {
					sum++;
					sx = i; sy = j;
				}
			}
		}
		if (sx == -1 && sy == -1) {
			System.out.println(-1);
			return;
		}
		diff = sum - k;
		bfs(sx, sy);
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				if (vis[i][j] && grid[i][j] == '.') {
					System.out.print('.');
				} else if (!vis[i][j] && grid[i][j] == '.') {
					System.out.print('X');
				} else {
					System.out.print('#');
				}
			}
			System.out.println();
		}
    }
}

复杂度分析

  • 时间复杂度: O ( n × m ) O(n × m) O(n×m)
  • 空间复杂度: O ( n × m ) O(n × m) O(n×m)

你可能感兴趣的:(●,搜索)