NENU 蓝桥杯训练赛(dfs+bfs)题解

NENU 蓝桥杯训练赛(dfs+bfs)题解

NENU 蓝桥杯训练赛(dfs+bfs)

A 棋盘问题

题意:

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 k k k 个棋子的所有可行的摆放方案。

思路:

dfs时记录当前行、已用棋子个数和列状态(用二进制表示)。

import java.util.*;
import java.math.*;

public class Main {
	static char[][] G;
	static int n, k, ans;
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		while((n = cin.nextInt()) != -1 && (k = cin.nextInt()) != -1) {
			ans = 0;
			G = new char[n][n];
			String s;
			for(int i = 0;i < n; ++i) {
				s = cin.next();
				G[i] = s.toCharArray();
			}
			dfs(0, 0, 0);
			System.out.println(ans);
		}
		cin.close();
	}
	public static void dfs(int now_row, int sum, int col_status) {
		if(sum == k) {
			ans++;
			return ;
		}
		if(now_row < n) {
			dfs(now_row + 1, sum, col_status);
			for(int i = 0;i < n; ++i) {
				if(G[now_row][i] == '#' && (col_status & (1 << i)) == 0) {
					dfs(now_row + 1, sum + 1, (col_status | (1 << i)));
				}
			}
		}
	}
}

B Dungeon Master

题意:

三维空间走迷宫。

思路:

bfs。

import java.util.*;
import java.math.*;

class pos{
	int x, y, z, stp;
	pos() {
		x = y = z = stp = 0;
	}
	public void set(int x, int y, int z, int stp) {
		this.x = x;
		this.y = y;
		this.z = z;
		this.stp = stp;
	}
}

public class Main {
	static char[][][] G;
	static int[][][] vis;
	static int a, b, c;
	static int[] dx = {1, -1, 0, 0, 0, 0};
	static int[] dy = {0, 0, 1, -1, 0, 0};
	static int[] dz = {0, 0, 0, 0, 1, -1};
	public static int bfs(pos st, pos ed) {
		Queue<pos> q = new LinkedList<pos>();
		q.offer(st);
		vis[st.x][st.y][st.z] = 1;
		pos now;
		while((now = q.poll()) != null) {
			if(now.x == ed.x && now.y == ed.y && now.z == ed.z) {
				return now.stp;
			}
			for(int i = 0;i < 6; ++i) {
				int x = now.x + dx[i];
				int y = now.y + dy[i];
				int z = now.z + dz[i];
				if((x >= 0 && x < a) && (y >= 0 && y < b) && (z >= 0 && z < c) && G[x][y][z] != '#' && vis[x][y][z] == 0) {
					pos tmp = new pos();
					tmp.set(x, y, z, now.stp + 1);
					q.offer(tmp);
					vis[x][y][z] = 1;
				}
			}
		}
		return Integer.MAX_VALUE;
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		while((a = cin.nextInt()) != 0 && (b = cin.nextInt()) != 0 && (c = cin.nextInt()) != 0) {
			G = new char[a][b][c];
			vis = new int[a][b][c];
			String s;
			pos st = new pos();
			pos ed = new pos();
			for(int i = 0;i < a; ++i) {
				for(int j = 0;j < b; ++j) {
					s = cin.next();
					G[i][j] = s.toCharArray();
					for(int k = 0;k < c; ++k) {
						vis[i][j][k] = 0;
						if(G[i][j][k] == 'S')st.set(i, j, k, 0);
						if(G[i][j][k] == 'E')ed.set(i, j, k, 0);
					}
				}
			}
			int ans = bfs(st, ed);
			if(ans != Integer.MAX_VALUE) {
				System.out.println("Escaped in " + ans + " minute(s).");
			}
			else {
				System.out.println("Trapped!");
			}
		}
		cin.close();
	}
}


C Catch That Cow

题意:

给定 N , K N,K N,K,问最少对 N N N 进行几次操作可以得到 K K K

  • − 1 -1 1
  • + 1 +1 +1
  • × \times × 2

思路:

N , K ∈ [ 0 , 100000 ] N,K \in [0,100000] N,K[0,100000] 直接bfs即可, v i s [ i ] vis[i] vis[i] 标记是否到过 i i i

import java.util.*;
import java.math.*;

class pos{
	int x, stp; 
	pos(){
		x = stp = 0;
	}
	public void set(int x, int stp) {
		this.x = x;
		this.stp = stp;
	}
}

public class Main {
	static int[] vis = new int[100005];
	static int n, k;
	public static int bfs() {
		Queue<pos> q = new LinkedList<pos>();
		pos st = new pos();
		st.set(n, 0);
		q.offer(st);
		vis[st.x] = 1;
		pos now;
		while((now = q.poll()) != null) {
			if(now.x == k) {
				return now.stp;
			}
			for(int i = 1;i <= 3; ++i) {
				int x = -1;
				pos tmp = new pos();
				if(i == 1)x = now.x - 1;
				if(i == 2)x = now.x + 1;
				if(i == 3)x = 2 * now.x;
				if((x >= 0 && x <= 100000) && vis[x] == 0) {
					tmp.set(x, now.stp + 1);
					q.offer(tmp);
					vis[x] = 1;
				}
			}
		}
		return Integer.MAX_VALUE;
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		for(int i = 0;i <= 100000; ++i)vis[i] = 0;
		n = cin.nextInt();
		k = cin.nextInt();
		System.out.println(bfs());
		cin.close();
	}
}


D Fliptile

题意:

给你一个 01 01 01 矩阵,矩阵大小为 M × N M \times N M×N ( 1 < = M , N < = 15 ) (1 <= M , N <= 15) (1<=M,N<=15)
每次操作选择一个格子,使得该格子与上下左右四个格子的值翻转。
至少多少次操作可以使得矩阵中所有的值变为 0 0 0
请输出翻转方案,若没有方案,输出" I M P O S S I B L E IMPOSSIBLE IMPOSSIBLE ” 。

思路:

暴力枚举第一行的翻转状态,然后判断是否可行。

import java.io.*;
import java.util.*;
import java.math.*;

public class Main{
	static int n, m, tmp[][], G[][], res[][], dx[] = {-1, 1, 0, 0, 0}, dy[] = {0, 0, -1, 1, 0};
	public static int getcolor(int x, int y) {
		int cnt = G[x][y];
		for(int i = 0;i <= 4; ++i) {
			int xx = x + dx[i], yy = y + dy[i];
			if(xx >= 1 && xx <= n && yy >= 1 && yy <= m) {
				cnt += tmp[xx][yy];
			}
		}
		return cnt & 1;
	}
	public static int calc() {
		for(int i = 2;i <= n; ++i) {
			for(int j = 1;j <= m; ++j) {
				if(getcolor(i - 1, j) == 1) {
					tmp[i][j] = 1;
				}
			}
		}
		for(int i = 1; i <= m; ++i) {
			if(getcolor(n, i) == 1) {
				return Integer.MAX_VALUE;
			}
		}
		int res = 0;
		for(int i = 1;i <= n; ++i) {
			for(int j = 1;j <= m; ++j) {
				res += tmp[i][j];
			}
		}
		return res;
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		n = cin.nextInt();
		m = cin.nextInt();
		G = new int[n + 1][m + 1];
		res = new int[n + 1][m + 1];
		for(int i = 1;i <= n; ++i) {
			for(int j = 1;j <= m; ++j) {
				G[i][j] = cin.nextInt();
			}
		}
		int ans = Integer.MAX_VALUE;
		for(int k = 0;k < (1 << m); ++k) {
			tmp = new int[n + 1][m + 1];
			for(int j = 1;j <= m; ++j) {
				if((k & (1 << (j - 1))) != 0) {
					tmp[1][j] = 1;
				}
			}
			int now = calc();
			if(now < ans) {
				ans = now;
				for(int i = 1;i <= n; ++i) {
					for(int j = 1;j <= m; ++j) {
						res[i][j] = tmp[i][j];
					}
				}
			}
		}
		if(ans == Integer.MAX_VALUE) {
			System.out.println("IMPOSSIBLE");
		}
		else {
			for(int i = 1;i <= n; ++i) {
				for(int j = 1;j <= m; ++j) {
					if(j > 1)System.out.print(" ");
					System.out.print(res[i][j]);
				}
				System.out.println();
			}
		}
	}
}

E Find The Multiple

题意:

给定一个正整数 n n n ,找出 n n n 的非零倍数 m m m ,其十进制表示形式仅包含数字 0 0 0 1 1 1

思路:

n ∈ [ 1 , 200 ] n \in [1,200] n[1,200] ,bfs, v i s [ i ] vis[i] vis[i] 标记是否有数 m o d mod mod n = = i n==i n==i

import java.util.*;
import java.math.*;

class num{
	BigInteger x;
	int re;
	
	public void set(BigInteger x, int re) {
		this.x = x;
		this.re = re;
	}
}

public class Main {
	static int vis[] = new int[205];
	public static BigInteger calc(BigInteger x, int n) {
		for(int i = 0;i <= 200; ++i) {
			vis[i] = 0;
		}
		Queue<num> q = new LinkedList<num>();
		if(n == 1) {
			return BigInteger.ONE;
		}
		num fst = new num();
		fst.set(BigInteger.ONE, 1);
		vis[1] = 1;
		q.offer(fst);
		num now;
		while((now = q.poll()) != null) {
			for(int i = 1;i <= 2; ++i) {
				num snd = new num();
				int now_re = now.re * 10 % n;
				if(i == 1) {
					if(vis[now_re] == 0) {
						vis[now_re] = 1;
						snd.set(now.x.multiply(BigInteger.valueOf(10)), now_re);
					}
				}
				else {
					now_re = (now_re + 1) % n;
					if(vis[now_re] == 0) {
						vis[now_re] = 1;
						snd.set(now.x.multiply(BigInteger.valueOf(10)).add(BigInteger.ONE), now_re);
					}
				}
				if(snd.x != null) {
					if(snd.re == 0) {
						return snd.x;
					}
					q.offer(snd);
				}
			}
		}
		return BigInteger.valueOf(-1);
	}
	public static void test(){
		for(int i = 1;i <= 200; ++i) {
			System.out.println("a[" + i + "] = \"" + calc(BigInteger.valueOf(i), i) + "\";");
		}
		System.out.println("END");
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
//		test();
		String a[] = new String[205];
		a[1] = "1";
		a[2] = "10";
		a[3] = "111";
		a[4] = "100";
		a[5] = "10";
		a[6] = "1110";
		a[7] = "1001";
		a[8] = "1000";
		a[9] = "111111111";
		a[10] = "10";
		a[11] = "11";
		a[12] = "11100";
		a[13] = "1001";
		a[14] = "10010";
		a[15] = "1110";
		a[16] = "10000";
		a[17] = "11101";
		a[18] = "1111111110";
		a[19] = "11001";
		a[20] = "100";
		a[21] = "10101";
		a[22] = "110";
		a[23] = "110101";
		a[24] = "111000";
		a[25] = "100";
		a[26] = "10010";
		a[27] = "1101111111";
		a[28] = "100100";
		a[29] = "1101101";
		a[30] = "1110";
		a[31] = "111011";
		a[32] = "100000";
		a[33] = "111111";
		a[34] = "111010";
		a[35] = "10010";
		a[36] = "11111111100";
		a[37] = "111";
		a[38] = "110010";
		a[39] = "10101";
		a[40] = "1000";
		a[41] = "11111";
		a[42] = "101010";
		a[43] = "1101101";
		a[44] = "1100";
		a[45] = "1111111110";
		a[46] = "1101010";
		a[47] = "10011";
		a[48] = "1110000";
		a[49] = "1100001";
		a[50] = "100";
		a[51] = "100011";
		a[52] = "100100";
		a[53] = "100011";
		a[54] = "11011111110";
		a[55] = "110";
		a[56] = "1001000";
		a[57] = "11001";
		a[58] = "11011010";
		a[59] = "11011111";
		a[60] = "11100";
		a[61] = "100101";
		a[62] = "1110110";
		a[63] = "1111011111";
		a[64] = "1000000";
		a[65] = "10010";
		a[66] = "1111110";
		a[67] = "1101011";
		a[68] = "1110100";
		a[69] = "10000101";
		a[70] = "10010";
		a[71] = "10011";
		a[72] = "111111111000";
		a[73] = "10001";
		a[74] = "1110";
		a[75] = "11100";
		a[76] = "1100100";
		a[77] = "1001";
		a[78] = "101010";
		a[79] = "10010011";
		a[80] = "10000";
		a[81] = "1111111101";
		a[82] = "111110";
		a[83] = "101011";
		a[84] = "1010100";
		a[85] = "111010";
		a[86] = "11011010";
		a[87] = "11010111";
		a[88] = "11000";
		a[89] = "11010101";
		a[90] = "1111111110";
		a[91] = "1001";
		a[92] = "11010100";
		a[93] = "10000011";
		a[94] = "100110";
		a[95] = "110010";
		a[96] = "11100000";
		a[97] = "11100001";
		a[98] = "11000010";
		a[99] = "111111111111111111";
		a[100] = "100";
		a[101] = "101";
		a[102] = "1000110";
		a[103] = "11100001";
		a[104] = "1001000";
		a[105] = "101010";
		a[106] = "1000110";
		a[107] = "100010011";
		a[108] = "110111111100";
		a[109] = "1001010111";
		a[110] = "110";
		a[111] = "111";
		a[112] = "10010000";
		a[113] = "1011011";
		a[114] = "110010";
		a[115] = "1101010";
		a[116] = "110110100";
		a[117] = "10101111111";
		a[118] = "110111110";
		a[119] = "100111011";
		a[120] = "111000";
		a[121] = "11011";
		a[122] = "1001010";
		a[123] = "10001100111";
		a[124] = "11101100";
		a[125] = "1000";
		a[126] = "11110111110";
		a[127] = "11010011";
		a[128] = "10000000";
		a[129] = "100100001";
		a[130] = "10010";
		a[131] = "101001";
		a[132] = "11111100";
		a[133] = "11101111";
		a[134] = "11010110";
		a[135] = "11011111110";
		a[136] = "11101000";
		a[137] = "10001";
		a[138] = "100001010";
		a[139] = "110110101";
		a[140] = "100100";
		a[141] = "10011";
		a[142] = "100110";
		a[143] = "1001";
		a[144] = "1111111110000";
		a[145] = "11011010";
		a[146] = "100010";
		a[147] = "1100001";
		a[148] = "11100";
		a[149] = "110111";
		a[150] = "11100";
		a[151] = "1110001";
		a[152] = "11001000";
		a[153] = "10111110111";
		a[154] = "10010";
		a[155] = "1110110";
		a[156] = "1010100";
		a[157] = "10101101011";
		a[158] = "100100110";
		a[159] = "100011";
		a[160] = "100000";
		a[161] = "11101111";
		a[162] = "11111111010";
		a[163] = "1010111";
		a[164] = "1111100";
		a[165] = "1111110";
		a[166] = "1010110";
		a[167] = "11111011";
		a[168] = "10101000";
		a[169] = "10111101";
		a[170] = "111010";
		a[171] = "1111011111";
		a[172] = "110110100";
		a[173] = "1011001101";
		a[174] = "110101110";
		a[175] = "100100";
		a[176] = "110000";
		a[177] = "100101111";
		a[178] = "110101010";
		a[179] = "11010111";
		a[180] = "11111111100";
		a[181] = "1001111";
		a[182] = "10010";
		a[183] = "100101";
		a[184] = "110101000";
		a[185] = "1110";
		a[186] = "100000110";
		a[187] = "1001011";
		a[188] = "1001100";
		a[189] = "1010111010111";
		a[190] = "110010";
		a[191] = "11101111";
		a[192] = "111000000";
		a[193] = "11001";
		a[194] = "111000010";
		a[195] = "101010";
		a[196] = "110000100";
		a[197] = "1101000101";
		a[198] = "1111111111111111110";
		a[199] = "111000011";
		a[200] = "1000";
		while(cin.hasNext()) {
			int n = cin.nextInt();
			if(n == 0)break;
			else {
				System.out.println(a[n]);
			}
		}
		cin.close();
	}
}

F Prime Path

题意:

给定两个四位的素数 a , b a,b a,b a a a 可以改变某一位上的数字变成 c c c ,但只有当 c c c 也是四位的素数时才能进行这种改变。问 a a a 最少经过多少次上述变换才能变成 b b b

思路:

bfs, v i s [ i ] vis[i] vis[i] 标记四位素数 i i i 是否出现过。

import java.io.*;
import java.util.*;
import java.math.*;

class num{
	int x,stp;
	num(){
		x = stp = 0;
	}
	public void set(int x, int stp) {
		this.x = x;
		this.stp = stp;
	}
}

public class Main{
	static int vis[] = new int[100005];
	public static boolean isprime(int x) {
		if(x == 1)return false;
		for(int i = 2;i * i <= x; ++i) {
			if(x % i == 0)return false;
		}
		int i = 0;
		for(;i < 4 && x > 0; ++i) {
			x /= 10;
		}
		return i == 4 ? true : false;
	}
	public static int calc(int st, int ed) {
		for(int i = 0;i < 100000; ++i) {
			vis[i] = 0;
		}
		Queue<num> q = new LinkedList<num>();
		num fst = new num();
		fst.set(st, 0);
		vis[st] = 1;
		q.offer(fst);
		num now;
		while((now = q.poll()) != null) {
			if(now.x == ed) {
				return now.stp;
			}
			int a[] = new int[5];
			int b[] = new int[5];
			for(int i = 0;i < 4; ++i) {
				a[i] = 0;
			}
			for(int i = 0, j = now.x;i < 4 && j > 0; ++i, j /= 10) {
				a[i] = j % 10;
			}
			for(int i = 0;i < 4; ++i) {
				b[i] = a[i];
			}
			for(int i = 0;i < 4; ++i) {
				for(int j = 0;j < 10; ++j) {
					a[i] = j;
					num p = new num();
					p.x = a[0] + a[1] * 10 + a[2] * 100 + a[3] * 1000;
					if(vis[p.x] == 0 && isprime(p.x)) {
						p.stp = now.stp + 1;
						vis[p.x] = 1;
						q.offer(p);
					}
				}
				a[i] = b[i];
			}
		}
		return -1;
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int t = cin.nextInt();
		while(t-- > 0) {
			int n = cin.nextInt();
			int m = cin.nextInt();
			int ans = calc(n, m);
			System.out.println(ans == -1 ? "Impossible" : ans);
		}
	}
}

G Shuffle’m Up

题意:

给定两个长度为 n n n 的字符串 s 1 s1 s1 s 2 s2 s2 , 接着给出一个长度为 2 n 2n 2n 的字符串 s s s 。问将字符串 s 1 s1 s1 s 2 s2 s2 通过一定的变换变成 s s s 需要几次变换次数?

变换规则如下:

假设 s 1 = 12345 , s 2 = 67890 s1=12345,s2=67890 s1=12345,s2=67890

变换后的序列 s 12 = 6172839405 s12=6172839405 s12=6172839405

如果 s 12 s12 s12 s s s 完全相等那么输出变换次数

如果不完全相等, s s s 的前半部分作为 s 1 s1 s1 ,后半部分作为 s 2 s2 s2 ,重复上述过程。

思路:

模拟,变换 1000 1000 1000 次有解输出,无解输出 − 1 -1 1

import java.io.*;
import java.util.*;

public class Main{
	static char a1[], a2[] = new char[205]; 
	public static String calc(String s1, String s2, int n) {
		String res = "";
		for(int i = 0;i < n; ++i) {
			res += s2.charAt(i);
			res += s1.charAt(i);
		}
		return res.toString();
	}
	public static boolean check(String s1, String s2, int n) {
		for(int i = 0;i < n; ++i) {
			if(s1.charAt(i) != s2.charAt(i))return false;
		}
		return true;
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int t = cin.nextInt();
		for(int ca = 1;ca <= t; ++ca) {
			int n = cin.nextInt();
			String s1, s2, s;
			s1 = cin.next();
			s2 = cin.next();
			s = cin.next();
			int f = 0;
			for(int i = 1;i <= 1000; ++i) {
				String nows = calc(s1, s2, n);
				s1 = nows.substring(0, n);
				s2 = nows.substring(n, 2 * n);
				if(check(nows, s, 2 * n)) {
					System.out.println(ca + " " + i);
					f = 1;
					break;
				}
			}
			if(f == 0) {
				System.out.println(ca + " " + -1);
			}
		}
	}
}

H Pots

题意:

小明给你两个容器,分别能装下A升水和B升水,并且可以进行以下操作:

  • F I L L ( i ) FILL(i) FILL(i) 将第 i i i 个容器从水龙头里装满 ( 1 ≤ i ≤ 2 ) (1 ≤ i ≤ 2) (1i2)
  • D R O P ( i ) DROP(i) DROP(i) 将第 i i i 个容器抽干
  • P O U R ( i , j ) POUR(i,j) POUR(i,j) 将第 i i i 个容器里的水倒入第 j j j 个容器

问最少操作数使其中任何一个容器里的水恰好有C升并给出操作过程。

思路:

bfs + 分类讨论, v i s [ x ] [ y ] vis[x][y] vis[x][y] 表示到达第一个杯子 x x x 升水,第二个杯子 y y y 升水的最少操作数,用 p r e [ x ] [ y ] pre[x][y] pre[x][y] 记录前驱状态。

import java.io.*;
import java.util.*;
import java.math.*;

class cup{
	int x,y;
	cup(){
		x = y = 0;
	}
	cup(int x, int y){
		this.x = x;
		this.y = y;
	}
	public void set(int x, int y) {
		this.x = x;
		this.y = y;
	}
}

public class Main{
	static int vis[][];
	static String s[][];
	static cup pre[][], ed;
	public static int calc(int A, int B, int C) {
		for(int i = 0;i <= A; ++i) {
			for(int j = 0;j <= B; ++j) {
				vis[i][j] = 0;
			}
		}
		Queue<cup> q = new LinkedList<cup>();
		q.offer(new cup(0, 0));
		vis[0][0] = 1;
		cup now;
		while((now = q.poll()) != null) {
			int x = now.x, y = now.y;
			if(x == C || y == C) {
				ed = new cup(x, y);
				return vis[x][y];
			}
			//fill 1
			if(x != A) {
				if(vis[A][y] == 0) {
					vis[A][y] = vis[x][y] + 1;
					s[A][y] = "FILL(1)";
					pre[A][y] = new cup(x, y);
					q.offer(new cup(A, y));
				}
			}
			//fill 2
			if(y != B) {
				if(vis[x][B] == 0) {
					vis[x][B] = vis[x][y] + 1;
					s[x][B] = "FILL(2)";
					pre[x][B] = new cup(x, y);
					q.offer(new cup(x, B));
				}
			}
			//drop 1
			if(x != 0) {
				if(vis[0][y] == 0) {
					vis[0][y] = vis[x][y] + 1;
					s[0][y] = "DROP(1)";
					pre[0][y] = new cup(x, y);
					q.offer(new cup(0, y));
				}
			}
			//drop 2
			if(y != 0) {
				if(vis[x][0] == 0) {
					vis[x][0] = vis[x][y] + 1;
					s[x][0] = "DROP(2)";
					pre[x][0] = new cup(x, y);
					q.offer(new cup(x, 0));
				}
			}
			//1 -> 2
			int detal = Math.min(x, B - y);
			int nowx = x - detal, nowy = y + detal;
			if(vis[nowx][nowy] == 0) {
				vis[nowx][nowy] = vis[x][y] + 1;
				s[nowx][nowy] = "POUR(1,2)";
				pre[nowx][nowy] = new cup(x, y);
				q.offer(new cup(nowx, nowy));
			}
			//2 -> 1
			detal = Math.min(A - x, y);
			nowx = x + detal;
			nowy = y - detal;
			if(vis[nowx][nowy] == 0) {
				vis[nowx][nowy] = vis[x][y] + 1;
				s[nowx][nowy] = "POUR(2,1)";
				pre[nowx][nowy] = new cup(x, y);
				q.offer(new cup(nowx, nowy));
			}
		}
		return -1;
	}
	public static void cout(int x, int y) {
		if(pre[x][y] == null) {
			return ;
		}
		cout(pre[x][y].x, pre[x][y].y);
		System.out.println(s[x][y]);
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int A,B,C;
		A = cin.nextInt();
		B = cin.nextInt();
		C = cin.nextInt();
		vis = new int[A + 5][B + 5];
		pre = new cup[A + 5][B + 5];
		s = new String[A + 5][B + 5];
		int ans = calc(A, B, C);
		System.out.println(ans == -1 ? "impossible" : ans - 1);
		cout(ed.x, ed.y);
	}
}

I Fire!

题意:

乔在迷宫中工作。不幸的是,迷宫的一部分着火了,迷宫的主人没有制定火灾的逃跑计划。请帮助乔逃离迷宫。根据乔在迷宫中的位置以及迷宫的哪个方块着火,你必须确定火焰烧到他之前,乔是否可以离开迷宫,如果能离开他能跑多快。乔和火每分钟移动一个方格,上、下、左、右,四个方向中的一个。火势向四个方向同时蔓延。乔可以从迷宫的任何一个边界逃离迷宫。无论是乔还是火都不会到达有墙的位置。
# \# # 代表墙
. . . 代表空地,火和乔是可通行的
J J J 乔在迷宫中最初的位置,火和乔是可通行的
F F F 代表火
在每组测试中只有一个 J J J

思路:

bfs,先移动火,再移动人。

import java.io.*;
import java.util.*;
import java.math.*;

class pos{
	int x, y, op;
	pos(){
		x = y = op = 0;
	}
	pos(int x, int y, int op){
		this.x = x;
		this.y = y;
		this.op = op;
	}
	public void set(int x, int y, int op) {
		this.x = x;
		this.y = y;
		this.op = op;
	}
}

public class Main{
	static int n, m, vis1[][], vis2[][], dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
	static char G[][];
	public static int calc(int x1, int y1) {
		Queue<pos> q = new LinkedList<pos>();
		for(int i = 1;i <= n; ++i) {
			for(int j = 1;j <= m; ++j) {
				if(G[i][j] == 'F') {
					vis1[i][j] = 1;
					q.offer(new pos(i, j, 2));
				}
			}
		}
		vis1[x1][y1] = 1;
		q.offer(new pos(x1, y1, 1));
		pos now;
		while((now = q.poll()) != null) {
			int x = now.x, y = now.y;
			for(int i = 0;i < 4; ++i) {
				int xx = x + dx[i], yy = y + dy[i];
				if(xx >= 1 && xx <= n && yy >= 1 && yy <= m && G[xx][yy] == '.' && vis1[xx][yy] == 0) {
					vis1[xx][yy] = vis1[x][y] + 1;
					q.offer(new pos(xx, yy, now.op));
				}
				if(xx == 0 || xx == n + 1 || yy == 0 || yy == m + 1 && vis1[xx][yy] == 0) {
					if(now.op == 1)return vis1[x][y];
				}
			}
		}
		return -1;
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int t = cin.nextInt();
		for(int ca = 1;ca <= t; ++ca) {
			n = cin.nextInt();m = cin.nextInt();
			vis1 = new int[n + 5][m + 5];
			vis2 = new int[n + 5][m + 5];
			G = new char[n + 5][m + 5];
			String s;
			int x1, y1;
			x1 = y1 = 0;
			for(int i = 1;i <= n; ++i) {
				s = cin.next();
				for(int j = 1;j <= m; ++j) {
					G[i][j] = s.charAt(j - 1);
					if(G[i][j] == 'J') {
						x1 = i;y1 = j;
					}
				}
			}
			int ans = calc(x1, y1);
			System.out.println(ans == -1 ? "IMPOSSIBLE" : ans);
		}
	}
}

J 迷宫问题

题意:

一个 5 × 5 5 \times 5 5×5 的二维数组,表示一个迷宫。其中的 1 1 1 表示墙壁, 0 0 0 表示可以走的路,只能横着走或竖着走,不能斜着走,求从左上角到右下角的最短路线。

思路:

bfs, v i s [ x ] [ y ] vis[x][y] vis[x][y] 记录步数,用 p r e [ x ] [ y ] pre[x][y] pre[x][y] 记录前驱状态,表示到 ( x , y ) (x,y) (x,y) 的上一步在哪里。

import java.io.*;
import java.util.*;
import java.math.*;

class pos{
	int x,y;
	pos(){
		x = y = 0;
	}
	public void set(int x, int y) {
		this.x = x;
		this.y = y;
	}
}

public class Main{
	static int vis[][] = new int[10][10];
	static int G[][] = new int[10][10];
	static pos pre[][] = new pos[10][10];
	static int dx[] = {0, 0, -1, 1}, dy[]  = {-1, 1, 0, 0};
	public static boolean ck(int x, int y) {
		if(x >= 0 && x < 5 && y >= 0 && y < 5 && G[x][y] == 0)return true;
		return false;
	}
	public static void cout(int x, int y) {
		if(x == 0 && y == 0) {
			System.out.println("(" + x + ", " + y + ")");
			return ;
		}
		cout(pre[x][y].x, pre[x][y].y);
		System.out.println("(" + x + ", " + y + ")");
	}
	public static void calc() {
		for(int i = 0;i < 10; ++i) {
			for(int j = 0;j < 10; ++j) {
				vis[i][j] = 0;
			}
		}
		Queue<pos> q = new LinkedList<pos>();
		pos fst = new pos();
		fst.set(0, 0);
		vis[0][0] = 1;
		q.offer(fst);
		pos now;
		while((now = q.poll()) != null) {
			if(now.x == 4 && now.y == 4) {
				break;
			}
			for(int i = 0;i < 4; ++i) {
				int xx = now.x + dx[i];
				int yy = now.y + dy[i];
				if(ck(xx, yy) && vis[xx][yy] == 0) {
					vis[xx][yy] = vis[now.x][now.y] + 1;
					pre[xx][yy] = now;
					pos scnd = new pos();
					scnd.set(xx, yy);
					q.offer(scnd);
				}
			}
		}
		cout(4, 4);
		return ;
	}
	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		for(int i = 0;i < 5; ++i) {
			for(int j = 0;j < 5; ++j) {
				G[i][j] = cin.nextInt();
			}
		}
		calc();
	}
}

你可能感兴趣的:(ACM,深度优先,蓝桥杯,宽度优先)