一、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();
}
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,