---
tags: 解題報告
---
# j125. 4. 蓋步道
題目連結: [Zerojudge](https://zerojudge.tw/ShowProblem?problemid=j125)
## 題目說明
給一數字 $n$ 與 $n*n$ 的陣列, 求出能由左上走到右下所需的最小數字差及所需步數
## 想法
1. 輸入
2. 二分搜
3. BFS
## 參考答案
:::spoiler 點我展開
Runtime: 0.1s
Memory: 1008KB
時間複雜度: $O(log(n^2))$
空間複雜度: $O(2n^2)$
```cpp=
#include<bits/stdc++.h>
using namespace std;
int area[301][301];
int move_x[4]={1, -1, 0, 0},
move_y[4]={0, 0, 1, -1};
int visted[301][301];
int n;
void init(){
for (int i=1; i<=n; i++){
for (int j=1; j<=n; j++) visted[i][j]=-1;
}
}
void bfs(int high){
init();
queue<pair<int, int> > q;
q.push(make_pair(1, 1));
visted[1][1] = 0;
while (q.size() > 0){
pair<int, int> p = q.front();
q.pop();
int x = p.first,
y = p.second;
for (int m=0; m<4; m++){
int tx = x + move_x[m],
ty = y + move_y[m];
if (tx <= 0 or ty <= 0 or tx > n or ty > n) continue;
if (abs(area[tx][ty] - area[x][y]) <= high and (visted[tx][ty] == -1)){
q.push(make_pair(tx, ty));
visted[tx][ty] = visted[x][y]+1;
}
}
}
}
signed main(){
cin>>n;
for (int i=1; i<=n; i++){
for (int j=1; j<=n; j++) cin>>area[i][j];
}
int l=0, r=1e6;
while (l <= r){
int m = (l+r)/2;
bfs(m);
if (visted[n][n] != -1) r = m-1;
else l = m+1;
}
bfs(l);
cout<<l<<"\n"<<visted[n][n];
}
```
[Github](https://github.com/henryleecode23/solve_record/tree/main/zerojudge/j125)
:::
## 解釋
### 輸入
建立 $300*300$ 的陣列做儲存
這裡開$301*301$之後計算比較直覺
```cpp=4
int area[301][301];
```
搭配巢狀迴圈接收輸入
```cpp=39
cin>>n;
for (int i=1; i<=n; i++){
for (int j=1; j<=n; j++) cin>>area[i][j];
}
```
### [二分搜](/R_LXj5WkRwWJAVHfG3vEiA)
因為高度範圍最大能到$10^6$, 如果從1開始一個一個數字下去跑很可能會TLE
因此使用二分搜加快速度, 來找出能走到終點的最大高度差
如果能走到終點就把高度往下, 走不到就往上找
```cpp=44
while (l <= r){
int m = (l+r)/2;
bfs(m);
if (visted[n][n] != -1) r = m-1;
else l = m+1;
}
```
### [BFS](/M-EVnoAlR9KD2Cn21wz5NA)
找最短路徑長度用BFS是基礎
```cpp=
void bfs(int high){
init();
queue<pair<int, int> > q;
q.push(make_pair(1, 1));
visted[1][1] = 0;
while (q.size() > 0){
pair<int, int> p = q.front();
q.pop();
int x = p.first,
y = p.second;
for (int m=0; m<4; m++){
int tx = x + move_x[m],
ty = y + move_y[m];
if (tx <= 0 or ty <= 0 or tx > n or ty > n) continue;
if (abs(area[tx][ty] - area[x][y]) <= high and (visted[tx][ty] == -1)){
q.push(make_pair(tx, ty));
visted[tx][ty] = visted[x][y]+1;
}
}
}
}
```
## 心得
這題是2022 10月的APCS 第四題, 當初考的時候還不知道二分搜這東西結果只撈到部份分
現在覺得二分搜超神
---
{%hackmd @henry-lee-code23/dark-theme %}