2022-02-16 P1141 01迷宫

202 阅读1分钟

题目链接: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;//对当前连通块赋值(表示最大连通了多少个)
		}
	}

}