BFS
走迷宫
给定一个 n×m的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0表示可以走的路,1 表示不可通过的墙壁。
最初,有一个人位于左上角 (1,1) 处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。
请问,该人从左上角移动至右下角 (n,m) 处,至少需要移动多少次。
数据保证 (1,1) 处和 (n,m) 处的数字为 0,且一定至少存在一条通路。
输入格式
第一行包含两个整数 n 和 m。
接下来 n 行,每行包含 m 个整数(0 或 1),表示完整的二维数组迷宫。
输出格式
输出一个整数,表示从左上角移动至右下角的最少移动次数。
数据范围
1≤n,m≤100
输入样例:
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出样例:
8
import java.io.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
static Scanner sc = new Scanner(System.in);
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st = new StreamTokenizer(br);
static PrintWriter pw=new PrintWriter(new OutputStreamWriter(System.out));
public static int nextInt()throws Exception{
st.nextToken();
return (int)st.nval;
}
public static long nextLong()throws Exception {
st.nextToken();
return (long)st.nval;
}
public static String next()throws Exception{
st.nextToken();
return st.sval;
}
public static double nextDouble()throws Exception{
st.nextToken();
return (double) st.nval;
}
public static String nextLine()throws Exception {
return br.readLine();
}
static int m;
static int n;
static Queue<pair>q=new LinkedList<>();
static int[][]dir={{1,0},{-1,0},{0,1},{0,-1}};
static int[][]a=new int[101][101];
static int[][]b=new int[101][101];
public static class pair{
int x;
int y;
int step=0;
public pair(int x, int y, int step) {
this.x = x;
this.y = y;
this.step = step;
}
}
static int bfs(){
int x,y;
q.add(new pair(0,0,0));
while(!q.isEmpty()){
pair p=q.poll();
if(p.x==m-1&&p.y==n-1){
return p.step;
}
for(int i=0;i<4;i++){
x=p.x+dir[i][0];
y=p.y+dir[i][1];
if(x>=0&&x<m&&y>=0&&y<n&&a[x][y]==0&&b[x][y]==0){
b[x][y]=1;
q.add(new pair(x,y,p.step+1));
}
}
}
return 0;
}
public static void main(String[] args)throws Exception {
m=nextInt();
n=nextInt();
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
a[i][j]=nextInt();
}
}
System.out.println(bfs());
}
}
DFS
迷宫
一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由 n∗n 的格点组成,每个格点只有2种状态,.
和#
,前者表示可以通行后者表示不能通行。
同时当Extense处在某个格点时,他只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Extense想要从点A走到点B,问在不走出迷宫的情况下能不能办到。
如果起点或者终点有一个不能通行(为#),则看成无法办到。
注意:A、B不一定是两个不同的点。
输入格式
第1行是测试数据的组数 k,后面跟着 k 组输入。
每组测试数据的第1行是一个正整数 n,表示迷宫的规模是 n∗n 的。
接下来是一个 n∗n 的矩阵,矩阵中的元素为.
或者#
。
再接下来一行是 4 个整数 ha,la,hb,lb描述 AA 处在第 haha 行, 第 la 列,B 处在第 hb 行, 第 lb 列。
注意到 ha,la,hb,lb 全部是从 0 开始计数的。
输出格式
k行,每行输出对应一个输入。
能办到则输出“YES”,否则输出“NO”。
数据范围
1≤n≤100
输入样例:
2
3
.##
..#
#..
0 0 2 2
5
.....
###.#
..#..
###..
...#.
0 0 4 0
输出样例:
YES
NO
import java.io.*;
import java.util.*;
public class Main{
static Scanner sc = new Scanner(System.in);
static BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st=new StreamTokenizer(br);
static int nextInt() throws Exception{
st.nextToken();
return (int)st.nval;
}
static double nextDouble() throws Exception{
st.nextToken();
return (double)st.nval;
}
static long nextLong() throws Exception{
st.nextToken();
return (long)st.nval;
}
static String next() throws Exception{
st.nextToken();
return st.sval;
}
static String nextLine() throws Exception{
return br.readLine();
}
static int N=110,row,col;
static char[][] a=new char[N][N];
static int[][] dir=new int[][]{{0,1},{0,-1},{1,0},{-1,0}};
public static void main(String[] args) throws Exception{
int m=Integer.valueOf(nextLine());
while(m-->0){
int n=Integer.valueOf(nextLine());
row=col=n;
for(int i=0;i<n;i++){
String s=nextLine();
for(int j=0;j<n;j++){
a[i][j]=s.charAt(j);
}
}
String[] ss=nextLine().split(" ");
int x1=Integer.parseInt(ss[0]);
int y1=Integer.parseInt(ss[1]);
int x2=Integer.parseInt(ss[2]);
int y2=Integer.parseInt(ss[3]);
boolean[][] vis=new boolean[n][n];
if(a[x1][y1]=='#'||a[x2][y2]=='#'){
System.out.println("NO");
} else if (x1==x2&&y1==y2){
System.out.println("YES");
} else if(dfs(x1,y1,x2,y2,vis)){
System.out.println("YES");
}else{
System.out.println("NO");
}
}
}
public static boolean dfs(int x1,int y1,int x2,int y2,boolean[][] vis) {
for (int i = 0; i < 4; i++) {
int nx = x1 + dir[i][0];
int ny = y1 + dir[i][1];
if(nx<0||nx>=row||ny<0||ny>=col||a[nx][ny]=='#'||vis[nx][ny])continue;
vis[nx][ny]=true;
if(nx==x2&&ny==y2)return true;
if(dfs(nx,ny,x2,y2,vis))return true;
}
return false;
}
}
并查集
合根植物
题目描述
w星球的一个种植园,被分成 m * n 个小格子(东西方向m行,南北方向n列)。每个格子里种了一株合根植物。
这种植物有个特点,它的根可能会沿着南北或东西方向伸展,从而与另一个格子的植物合成为一体。
如果我们告诉你哪些小格子间出现了连根现象,你能说出这个园中一共有多少株合根植物吗?
输入格式
第一行,两个整数m,n,用空格分开,表示格子的行数、列数(1<m,n<1000)。
接下来一行,一个整数k,表示下面还有k行数据(0<k<100000)
接下来k行,第行两个整数a,b,表示编号为a的小格子和编号为b的小格子合根了。
格子的编号一行一行,从上到下,从左到右编号。
比如:5 * 4 的小格子,编号:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
17 18 19 20
输出格式
多少株
样例输入
复制
5 4 16 2 3 1 5 5 9 4 8 7 8 9 10 10 11 11 12 10 14 12 16 14 18 17 18 15 19 19 20 9 13 13 17
样例输出
复制
5
import java.util.Arrays;
import java.util.Scanner;
public class Main{
static int inf=0x3f3f3f3f;
static int maxn=10051005;
static int m,n,k,ans;
static int[] p=new int[maxn];
static Scanner sc=new Scanner(System.in);
static boolean[] vis=new boolean[maxn];
public static void init(){
Arrays.fill(vis,false);
for (int i = 1; i <= n * m; i++) {
p[i]=i;
}
}
public static int find(int x){
if(x!=p[x]){
return p[x]=find(p[x]);
}return x;
}
public static void join(int x, int y){
int xx=find(x);
int yy=find(y);
if(xx!=yy)p[yy]=xx;
}
public static void main(String[] args) {
m= sc.nextInt();
n= sc.nextInt();
k= sc.nextInt();
init();
while (k-->0){
int x,y;
x= sc.nextInt();
y= sc.nextInt();
join(x,y);
}
for(int i=1;i<=m*n;i++){
vis[find(i)]=true;
}
for (int i = 1; i <= n * m; i++) {
if(vis[i])ans++;
}
System.out.println(ans);
}
}