版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zxzxzx0119/article/details/85337294
POJ 3126 & 2251 & 1321 & 3278 (DFS | BFS)
POJ - 3126 - Prime Path
题目链接
题目大意
第一个数T
代表测试样例个数,下面每一行是一个测试样例,每行输入两个数a
、b
,这两个数都是1000~9999
之间的素数,现在要求你从第一个数变成第二个数,每次变换可以(只可以)改变其中的一个数字,而且改变之后的那个数必须是素数,问能否经过有限次的这样变化,将第一个素数a
变成第二个素数b
,要你求最少的变化步数。
Sample Input
3
1033 8179
1373 8017
1033 1033
Sample Output
6
7
0
解析
相当于求无权图的最短路径(有权图用dijkstra
),用BFS
即可。
- 筛素数可以使用埃拉托斯特尼筛法,这个在
bfs
判断下一个节点进入队列时使用; - 然后主要就是每次变化四个数,每个数从
0~9
之间变化,得到下一个节点,然后判断是否满足条件,如果满足条件进队列即可。
import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
private static class Clazz{
public int num;
public int step;
public Clazz(int num, int step) {
this.num = num;
this.step = step;
}
}
public static final int MAX = 10000;
private static boolean[] sieve(){
boolean[] is_prime = new boolean[MAX];
Arrays.fill(is_prime, true);
is_prime[0] = is_prime[1] = false;
for(int i = 2; i < MAX; i++){
if(is_prime[i]){
for(int j = i*i; j < MAX; j += i)
is_prime[j] = false;
}
}
return is_prime;
}
public static int[] separate(int num){
int[] arr = new int[4];
int i = 0;
while(num > 0){
arr[i++] = num % 10;
num /= 10;
}
return arr;
}
public static int revert(int[] sep){
int res = 0;
for(int i = 0; i < sep.length; i++)
res += sep[i] * (int)Math.pow(10, i);
return res;
}
public static int bfs(int s, int e, boolean[] is_prime, boolean[] vis){
Queue<Clazz> queue = new LinkedList<Clazz>();
queue.add(new Clazz(s, 0));
vis[s] = true; // 和dijkstra不同, bfs一开始标记为true
int[] aArr, bArr; // 两个数组
while(!queue.isEmpty()){
Clazz cur = queue.poll();
if(e == cur.num){
return cur.step;
}
aArr = separate(cur.num);
for(int i = 0; i < 4; i++) {
bArr = Arrays.copyOf(aArr, aArr.length);
for(int j = 0; j < 10; j++){
bArr[i] = j;
int nxtNum = revert(bArr);
if(nxtNum > 1000 && nxtNum < 10000 && nxtNum != cur.num && !vis[nxtNum] && is_prime[nxtNum]){
vis[nxtNum] = true;
queue.add(new Clazz(nxtNum, cur.step + 1));
}
}
}
}
return -1;
}
public static void main(String[] args){
Scanner cin = new Scanner(new BufferedInputStream(System.in));
int T = cin.nextInt();
while(T-- > 0){
int s = cin.nextInt();
int e = cin.nextInt();
boolean[] is_prime = sieve(); // 筛选 0~10000的素数
boolean[] vis = new boolean[MAX];
int res = bfs(s, e, is_prime, vis);
System.out.println(res == -1 ? "Impossible" : res);
}
}
}
POJ - 2251 - Dungeon Master
题目链接
题目大意
给你一个三维的立方体牢笼,#
是不能走的,.
是可以走的,S
是起点,E
是终点,如果可以走(不是#
),你可以走上、下(上下相当于换楼层)、东、西、南、北 6 个方向,问你能否从S
到E
,如果可以,输出步数,否则输出Impossible
。
Sample Input
3 4 5
S....
.###.
.##..
###.#
#####
#####
##.##
##...
#####
#####
#.###
####E
1 3 3
S##
#E#
###
0 0 0
Sample Output
Escaped in 11 minute(s).
Trapped!
解析
三维的简单bfs
。
import java.io.BufferedInputStream;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
private static class State{
public int le;
public int x;
public int y;
public int step;
public State(int le, int x, int y, int step) {
this.le = le;
this.x = x;
this.y = y;
this.step = step;
}
}
public static int level, row, col;
public static String[][] str;
public static boolean success;
public static int[][] dir = { {0,-1,0}, {0, 0, 1}, {0, 1, 0}, {0, 0, -1}, {-1, 0, 0}, {1, 0, 0}};
public static boolean checkBoundary(int a, int b, int c){
return a >= 0 && a < level && b >= 0 && b < row && c >= 0 && c < col;
}
public static void bfs(State start, State end){
Queue<State>queue = new LinkedList<State>();
boolean[][][] vis = new boolean[level][row][col];
vis[start.le][start.x][start.y] = true;
queue.add(start);
while(!queue.isEmpty()){
State cur = queue.poll();
if(cur.le == end.le && cur.x == end.x && cur.y == end.y){
System.out.println("Escaped in " + cur.step + " minute(s).");
success = true;
break;
}
for(int i = 0; i < 6; i++){
int nle = cur.le + dir[i][0];
int nx = cur.x + dir[i][1];
int ny = cur.y + dir[i][2];
if(checkBoundary(nle, nx, ny) && str[nle][nx].charAt(ny) != '#' && !vis[nle][nx][ny] ){
vis[nle][nx][ny] = true;
queue.add(new State(nle, nx, ny , cur.step+1));
}
}
}
}
public static void main(String[] args) {
Scanner cin = new Scanner(new BufferedInputStream(System.in));
while (cin.hasNext()) {
level = cin.nextInt();
row = cin.nextInt();
col = cin.nextInt();
if(level == 0 && row == 0 && col == 0)
break;
str = new String[level][row];
for (int i = 0; i < level; i++) {
for (int j = 0; j < row; j++) {
str[i][j] = cin.next();
}
}
State start, end = null;
// find the end position
boolean flag = false;
for (int i = 0; i < level; i++) {
for (int j = 0; j < row; j++) {
for (int k = 0; k < col; k++) {
if (str[i][j].charAt(k) == 'E') {
end = new State(i, j, k, 0);
flag = true;
break;
}
}
if (flag)
break;
}
if (flag)
break;
}
success = false;
for (int i = 0; i < level; i++) {
for (int j = 0; j < row; j++) {
for (int k = 0; k < col; k++) {
if (str[i][j].charAt(k) == 'S') {
start = new State(i, j, k, 0);
bfs(start, end);
}
}
}
}
if (!success)
System.out.println("Trapped!");
}
}
}
POJ - 1321 - 棋盘问题
题目链接
题目大意
给你一个棋盘,但是棋盘上只有#
的可以摆放棋子(.
不行),且要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,摆放k
个棋子的所有可行的摆放方案C
。
Sample Input
2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1
Sample Output
2
1
解析
这个题目看上去和n皇后问题有点类似,但是要注意它们之间的不同:
n
皇后问题是必须每一行都要摆上皇后,这个题目是只需要摆放k
个棋子就可以;- 所以在递归的时候,不能摆放好了
curRow
(当前行以及之前行)之后去递归下一行,而是要去递归[curRow~n)
所有行都可以尝试摆放,只要摆放k
个就可以了,所以情况会多很多。 - 然后记录某一列是否摆放和
n
皇后一样,使用一个boolean
数组即可,同样记得递归之后c[j] = false
还原;
import java.io.*;
import java.util.Scanner;
public class Main {
private static int sum;
public static void dfs(String[] str, boolean[] c, int curRow, int k, int n) {
if (k == 0) {
sum++;
return;
}
// curRow前面的已经放好了,后面[curRow~n]之间的我都要试一下(注意不是皇后问题:只要试curRow+1的)
for (int i = curRow; i < n; i++) {
for (int j = 0; j < n; j++) { //尝试放在每一列
if (!c[j] && str[i].charAt(j) == '#') {
c[j] = true; // 将curRow棋子放到j列
dfs(str, c, i + 1, k - 1, n);
c[j] = false;
}
}
}
}
public static void main(String[] args) throws IOException {
Scanner cin = new Scanner(new BufferedInputStream(System.in));
while (cin.hasNext()) {
int n = cin.nextInt();
int k = cin.nextInt(); // k个棋子
if (n == -1 && k == -1)
break;
String[] str = new String[n];
for (int i = 0; i < n; i++)
str[i] = cin.next();
sum = 0;
dfs(str, new boolean[n], 0, k, n);
System.out.println(sum);
}
}
}
POJ - 3278 - Catch That Cow
题目链接
题目大意
给你两个数n、k
,要你按照下面的两种方式将n
变成k
,求最少的变化步数。
n = n+1
或者n = n-1
;n = n * 2
;
Sample Input
5 17
Sample Output
4
Note
The fastest way for Farmer John to reach the fugitive cow is to move along the following path: 5-10-9-18-17, which takes 4 minutes.
解析
简单的bfs
。注意n
可能大于k
。
import java.io.BufferedInputStream;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
public static class State{
public int num;
public int step;
public State(int num, int step) {
this.num = num;
this.step = step;
}
}
public static void bfs(State start, State end, boolean[] vis){
Queue<State>queue = new LinkedList<State>();
queue.add(start);
vis[start.num] = true;
while(!queue.isEmpty()){
State cur = queue.poll();
if(cur.num == end.num){
System.out.println(cur.step);
return;
}
int curPlus = cur.num + 1;
if(cur.num < end.num && !vis[curPlus]){
vis[curPlus] = true;
queue.add(new State(curPlus, cur.step+1));
}
int curSubtract = cur.num - 1;
if(cur.num > 0 && !vis[curSubtract]){
vis[curSubtract] = true;
queue.add(new State(curSubtract, cur.step+1));
}
int curMultiply = cur.num * 2;
if(cur.num < end.num && !vis[curMultiply]){
vis[curMultiply] = true;
queue.add(new State(curMultiply, cur.step+1));
}
}
}
public static void main(String[] args){
Scanner cin = new Scanner(new BufferedInputStream(System.in));
int n = cin.nextInt();
int k = cin.nextInt();
boolean[] vis = new boolean[2 * Math.max(n, k)]; // may n > k
bfs(new State(n, 0), new State(k, 0), vis);
}
}