描述
农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛位于点K(0<=K<=100000)。农夫有两种移动方式:
1、从X移动到X-1或X+1,每次移动花费一分钟
2、从X移动到2*X,每次移动花费一分钟
假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?
输入
两个整数,N和K
输出
一个整数,农夫抓到牛所要花费的最小分钟数
样例输入
5 17
样例输出
4
public class _24抓住那头牛 {
static int N, K;
static int MAXN = 100000;
static int[] visited = new int[MAXN + 10]; // 判重标记,visited[i] = true表示i已经扩展过
static class Step{
int x; // 位置
int steps; // 到达x所需的步数
public Step(int x, int steps) {
this.x = x;
this.steps = steps;
}
}
static Queue<Step> q = new LinkedList<Step>(); // 队列,即open表
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
K = sc.nextInt();
q.offer(new Step(N, 0));
visited[N] = 1;
while (!q.isEmpty()) {
Step s = q.peek(); // 查看队头元素
if (s.x == K) {
System.out.println(s.steps);
return ;
} else {
if (s.x - 1 >= 0 && visited[s.x-1] == 0) {
q.offer(new Step(s.x-1,s.steps+1));
visited[s.x-1] = 1;
}
if (s.x + 1 <= MAXN && visited[s.x+1] == 0) {
q.offer(new Step(s.x+1, s.steps+1));
visited[s.x+1] = 1;
}
if (s.x*2 <= MAXN && visited[s.x*2] == 0) {
q.offer(new Step(s.x*2, s.steps+1));
visited[s.x*2] = 1;
}
q.poll(); // 队头元素出队
}
}
}
}
Description
定义一个二维数组:
int maze[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,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
Input
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
Output
左上角到右下角的最短路径,格式如样例所示。
Sample Input
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
Sample Output
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
public class _25迷宫问题 {
static class Point {
public int x;
public int y;
public Point(int x,int y)
{
this.x = x;
this.y = y;
}
}
public static int[][] map = new int[6][6];
public static Point[][] address = new Point[6][6];
public static Queue<Point> queue = new LinkedList();
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
for(int i=0 ; i<5 ; i++)
{
for(int j=0 ; j<5 ; j++)
{
map[i][j] = in.nextInt();
}
}
bfs();
show();
}
public static void bfs()
{
int[] dx = {0,0,1,-1};
int[] dy = {1,-1,0,0};
queue.add(new Point(4,4));
while(!queue.isEmpty())
{
Point p = queue.peek();
queue.poll();
if(p.x==0&&p.y==0)break;
for(int i=0 ; i<4 ; i++)
{
int newX = p.x+dx[i];
int newY = p.y+dy[i];
// 超出边界
if(newX<0 || newY<0 || newX==5 || newY==5) {
continue;
}
// 已访问过
if(map[newX][newY] == 1) {
continue;
}
map[newX][newY]=1;
address[newX][newY]=p;
queue.add(new Point(newX,newY));
}
}
queue.clear();
}
public static void show()
{
int newX = 0;
int newY = 0;
while(true)
{
System.out.printf("(%d, %d)\n",newX, newY);
if(newX == 4 && newY == 4) {
break;
}
int tmp = newX; // ? 回溯
newX = address[newX][newY].x;
newY = address[tmp][newY].y;
}
}
}
题目:
已知一张地图(以二维矩阵的形式表示)以及佐助和鸣人的位置。地图上的每个位置都可以走到,只不过有些位置上有大蛇丸的手下,需要先打败大蛇丸的手下才能到这些位置。鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一个大蛇丸的手下。假设鸣人可以往上下左右四个方向移动,每移动一个距离需要花费1个单位时间,打败大蛇丸的手下不需要时间。如果鸣人查克拉消耗完了,则只可以走到没有大蛇丸手下的位置,不可以再移动到有大蛇丸手下的位置。佐助在此期间不移动,大蛇丸的手下也不移动。请问,鸣人要追上佐助最少需要花费多少时间?
输入
输入的第一行包含三个整数:M,N,T。代表M行N列的地图和鸣人初始的查克拉数量T。0 < M,N < 200,0 ≤ T < 10
后面是M行N列的地图,其中@代表鸣人,+代表佐助。*代表通路,#代表大蛇丸的手下。
输出
输出包含一个整数R,代表鸣人追上佐助最少需要花费的时间。如果鸣人无法追上佐助,则输出-1。
样例输入1
4 4 1
#@##
**##
###+
****
样例输入2
4 4 2
#@##
**##
###+
****
样例输出1
6
样例输出2
4
public class _26鸣人和佐助 {
static int M, N, T;
static int MAXN = 210;
static char[][] a = new char[MAXN][MAXN];
static class Pos {
int r,c,ck,steps;
public Pos() {
}
public Pos(int r, int c, int steps, int ck) {
this.r = r;
this.c = c;
this.steps = steps;
this.ck = ck;
}
}
static Queue<Pos> q = new LinkedList<Pos>();
// used[r][c][ck]表示位于(r,c)且查克拉数量为ck这种状态是否已被扩展
static int[][][] used = new int[MAXN][MAXN][15];
Pos s, e; // 起点和终点
// 定义方向数组
static int[][] dir = {{0, 1}, // 向右
{1, 0}, // 向下
{-1, 0}, // 向上
{0, -1}}; // 向左
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Pos s = new Pos();
Pos e = new Pos();
M = sc.nextInt();
N = sc.nextInt();
T = sc.nextInt();
for (int i=1; i<=M; ++i) {
String s1=sc.next();
for (int j=1; j<=N; ++j) {
a[i][j] = s1.charAt(j-1);
if (a[i][j] == '@') {
s = new Pos(i, j, 0, T);
} else if (a[i][j] == '+') {
a[i][j] = '*';
e = new Pos(i, j,-1,-1);
}
}
}
used[s.r][s.c][T] = 1;
q.offer(s);
while (!q.isEmpty()) {
Pos p = q.peek();
if (p.r == e.r && p.c == e.c) {
System.out.println(p.steps);
return;
}
q.poll();
for (int i=0; i<4; ++i) {
int newR = p.r + dir[i][0];
int newC = p.c + dir[i][1];
//遇到通路 不使用查克拉
if (a[newR][newC] == '*' && used[newR][newC][p.ck] == 0) {
used[newR][newC][p.ck] = 1;
q.offer(new Pos(newR, newC, p.steps+1, p.ck));
}
// 有大蛇丸手下 使用查克拉
if (a[newR][newC] == '#' && p.ck > 0 && used[newR][newC][p.ck-1] == 0) {
used[newR][newC][p.ck] = 1;
q.offer(new Pos(newR, newC, p.steps+1,p.ck-1));
}
}
}
System.out.println("-1");
}
}
广搜一般用于状态表示比较简单、求最优策略的问题
优点:是一种完备策略,即只要问题有解,它就一定可以找到解 。并且,广度优先搜索找到的解,还一定是路径最短的解。
缺点:盲目性较大,尤其是当目标节点距初始节点较远时,将产 生许多无用的节点,因此其搜索效率较低。需要保存所有扩展出 的状态,占用的空间大
深搜几乎可以用于任何问题
只需要保存从起始状态到当前状态路径上的节点。
根据题目要求凭借自己的经验和对两个搜索的熟练程度做出选择。