一、Problem
小明每天都要练功,练功中的重要一项是梅花桩。 小明练功的梅花桩排列成 n 行 m 列,相邻两行的距离为 1,相邻两列的距离也为 1。
小明站在第 1 行第 1 列上,他要走到第 n 行第 m 列上。小明已经练了一段时间,他现在可以一步移动不超过 d 的距离(直线距离)。
小明想知道,在不掉下梅花桩的情况下,自己最少要多少步可以移动到目标。
输入
输入的第一行包含两个整数 n,m,分别表示梅花桩的行数和列数。
第二行包含一个实数 dd(最多包含一位小数),表示小明一步可以移动的距离。
输出
输出一个整数,表示小明最少多少步可以到达目标。
输入
3 4
1.5
输出
3
二、Solution
方法一:bfs
0 分写法:D - dd 这种写法是有问题的,因为我想探索我一步最多能走几个梅花桩,所以
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static class Solution {
int n, m;
double d, exp = 1e-6;
final int[][] dir = {{1,0}, {0,1}, {1, 1}};
double dist(int x, int y, int x1, int y1) {
int xx = x1 - x, yy = y1 - y;
return Math.sqrt(xx*xx + yy*yy);
}
int bfs() {
Queue<Pos> q = new ArrayDeque<>();
q.add(new Pos(0, 0, 0));
boolean[][] vis = new boolean[n][m];
while (!q.isEmpty()) {
Pos t = q.poll();
if (t.x == n-1 && t.y == m-1)
return t.s;
for (int k = 0; k < 3; k++) {
double tt = d, dd = 0;
int tx = t.x, ty = t.y;
while (tt > dd) {
tx += dir[k][0];
ty += dir[k][1];
if (tx >= n || ty >= m || vis[tx][ty])
continue;
dd = dist(t.x, t.y, tx, ty);
tt -= dd;
q.add(new Pos(tx, ty, t.s+1));
vis[tx][ty] = true;
}
}
}
return 0;
}
void init() {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
n = sc.nextInt(); m = sc.nextInt();
d = sc.nextDouble();
System.out.println(bfs());
}
class Pos {
int x, y, s;
public Pos(int x, int y, int s) {
this.x = x; this.y = y; this.s = s;
}
}
}
public static void main(String[] args) throws IOException {
Solution s = new Solution();
s.init();
}
}
修改后的逻辑:得 9/30 分
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static class Solution {
int n, m, D;
double d, exp = 1e-6;
final int[][] dir = {{1,0}, {0,1}, {1, 1}};
double dist(int x, int y, int x1, int y1) {
int xx = x1 - x, yy = y1 - y;
return Math.sqrt(xx*xx + yy*yy);
}
int bfs() {
Queue<Pos> q = new ArrayDeque<>();
q.add(new Pos(1, 1, 0));
boolean[][] vis = new boolean[n+1][m+1];
while (!q.isEmpty()) {
Pos t = q.poll();
if (t.x == n && t.y == m)
return t.s;
for (int k = 0; k < 3; k++) {
int tx = t.x, ty = t.y;
while (tx <= Math.min(n, t.x+D) && ty <= Math.min(m, t.y+D)) {
tx += dir[k][0];
ty += dir[k][1];
if (tx > n || ty > m || vis[tx][ty])
continue;
double dd = dist(t.x, t.y, tx, ty);
if (d > dd) {
q.add(new Pos(tx, ty, t.s+1));
vis[tx][ty] = true;
}
}
}
}
return 0;
}
void init() {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
n = sc.nextInt(); m = sc.nextInt();
d = sc.nextDouble();
D = (int) d;
System.out.println(bfs());
}
class Pos {
int x, y, s;
public Pos(int x, int y, int s) {
this.x = x; this.y = y; this.s = s;
}
}
}
public static void main(String[] args) throws IOException {
Solution s = new Solution();
s.init();
}
}
怒改 3 个小时
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static class Solution {
int n, m, D;
double d, exp = 1e-6;
double dist(int x, int y, int x1, int y1) {
int xx = x1 - x, yy = y1 - y;
return Math.sqrt(xx*xx + yy*yy);
}
int bfs() {
Queue<Pos> q = new ArrayDeque<>();
q.add(new Pos(1, 1, 0));
boolean[][] vis = new boolean[n+1][m+1];
vis[1][1] = true;
while (!q.isEmpty()) {
Pos t = q.poll();
if (t.x == n && t.y == m)
return t.s;
for (int i = t.x; i <= Math.min(n, t.x+D); i++)
for (int j = t.y; j <= Math.min(m, t.y+D); j++) {
if (vis[i][j])
continue;
double dd = dist(t.x, t.y, i, j);
if (dd < d) {
q.add(new Pos(i, j, t.s+1));
vis[i][j] = true;
}
}
}
return 0;
}
void init() {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
n = sc.nextInt(); m = sc.nextInt();
d = sc.nextDouble();
D = (int) d;
System.out.println(bfs());
}
class Pos {
int x, y, s;
public Pos(int x, int y, int s) {
this.x = x; this.y = y; this.s = s;
}
}
}
public static void main(String[] args) throws IOException {
Solution s = new Solution();
s.init();
}
}
勾股定理可以不转化为实际距离,可以直接用 算,但有溢出风险。
但还是超时了… 18/30 吧…
复杂度分析
- 时间复杂度:,
- 空间复杂度:,
方法二:贪心
为什么要想得那么复杂呢?直接走对角线不好吗?
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static class Solution {
void init() {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
int n = sc.nextInt()-1, m = sc.nextInt()-1;
double d = sc.nextDouble();
double dd = Math.sqrt(n*n + m*m);
System.out.println((int) Math.ceil(dd/d));
}
}
public static void main(String[] args) throws IOException {
Solution s = new Solution();
s.init();
}
}
复杂度分析
- 时间复杂度:,
- 空间复杂度:,