题目链接:www.luogu.com.cn/problem/P11…
P1141 01迷宫
这道题主要考到bfs加上连通块,这里卡了我好久的问题就是连通块,如何保存连通块数据成了我一大难点,还有就是没有联想到连通块这个地方,本来这道题一开始能想到用bfs,但是在内存和时间上并不允许,只能满足70%的数据。
一代目:
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
static int n,m;//输入的n维矩阵,m个搜索数据
static char[][] map;//n维矩阵
static int[] station_x = {1,0,-1,0}; //遍历位置(上下左右)
static int[] station_y = {0,-1,0,1};//同上
static Queue<Pos> que = new LinkedList<>();//队列
static boolean[][] vis = new boolean[1000][1000];//判断是否遍历过
public static int bfs(int x,int y) {
que.add(new Pos(x,y,1));
vis[x][y] = true;
int tx,ty,tstep;
int step = 1;
int max = 1;//计算连通块数据
while(!que.isEmpty()) {
x = que.peek().x;
y = que.peek().y;
step = que.peek().step;
que.poll();
for(int i = 0; i < 4;i++) {
tx = x + station_x[i];
ty = y + station_y[i];
if(tx < 0 || ty < 0 || tx >=n || ty >= n)
continue;
if(vis[tx][ty])
continue;
if(map[tx][ty]==map[x][y])
continue;
que.add(new Pos(tx,ty,step + 1));
vis[tx][ty] = true;
max++;
}
}
return max;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
map = new char[n][n];
sc.nextLine();
for(int i = 0; i < n;i++) {
String s = sc.nextLine();
map[i] = s.toCharArray();
}
int[] arr = new int[m];
for(int i = 0;i < m;i++) {
int a = sc.nextInt();
int b = sc.nextInt();
arr[i] = bfs(a - 1,b - 1);//每次都要计算,时间肯定不够,因为m的数据在10的5次方,时间复杂度太高
vis = new boolean[1000][1000];//每次都要重新遍历,新创建,造成空间不足
}
for(int i = 0; i< m;i++)
System.out.println(arr[i]);
}
}
class Pos{
int x;
int y;
int step = 1;
public Pos(int x,int y,int step) {
this.x = x;
this.y = y;
this.step = step;
}
}
接下来的改良,首先是把数据保存下来,不需要重新遍历,如果遇到是同一个连通块,则可以不用重新计算,可以直接求出来。
因为输入和输出比较多,所以就顺便优化了下输入、输出
最终版
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public class Main01 {
static int n,m;
static int N = 1010;
static int M = 1000010;
static int[][] ans = new int[N][N];//保存数据
static char[][] map = new char[N][N];//n维矩阵
static boolean[][] st = new boolean[N][N];//判断是否遍历过
static int[] dx = {0,-1,0,1};//遍历方向(上下左右)
static int[] dy = {1,0,-1,0};
static Queue<int[]> que = new LinkedList<>();//队列
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//优化输入
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));//优化输出
public static void main(String[] args) throws Exception {
String[] str = br.readLine().split(" ");
//输入数据
n = Integer.parseInt(str[0]);
m = Integer.parseInt(str[1]);
for(int i = 0; i < n;i++) {
String str1 = br.readLine();
map[i] = str1.toCharArray();
}
for(int i = 0 ; i < m;i++) {
str = br.readLine().split(" ");
int sx = Integer.parseInt(str[0]);
int sy = Integer.parseInt(str[1]);
if(ans[sx - 1][sy - 1] != 0) {//如果当前数据不为0,说明前面已经算过了一次连通块,就不用再次进行bfs
bw.write(ans[sx - 1][sy - 1] + "\n");
continue;
}
bfs(sx - 1,sy - 1);//不然就bfs
bw.write(ans[sx - 1][sy - 1] + "\n");
}
bw.write("\n");
br.close();
bw.flush();
bw.close();
// for(int i =0; i < 2; i++) {
// for(int j = 0; j < 2; j++){
// System.out.printf("%d ", ans[i][j]);
// }
// System.out.println();
// }
//
}
public static void bfs(int x,int y) throws Exception {
List<int[]> list = new ArrayList<>();//保存遍历过的连通块
que.add(new int[] {x,y});//添加队列
list.add(new int[] {x,y});
st[x][y] = true;
int tx,ty;
int cnt = 1;//计算连通块数
//常见bfs模板
while(!que.isEmpty()) {
int[] a = que.poll();
for(int i = 0; i < dx.length;i++) {
tx = a[0] + dx[i];
ty = a[1] + dy[i];
if(tx < 0 || ty < 0 || tx >= n || ty >= n || st[tx][ty] || map[tx][ty] == map[a[0]][a[1]]) continue;
// System.out.println(tx + " " + ty);
que.add(new int[] {tx,ty} );
list.add(new int[] {tx,ty} );//添加当前点
st[tx][ty] = true;
cnt++;
}
}
for(int i = 0; i < list.size();i++) {
int[] t = list.get(i);
ans[t[0]][t[1]] = cnt;//对当前连通块赋值(表示最大连通了多少个)
}
}
}