# Week 11 BFS
:::info
時間:04/30 9:00 ~ 17:00
地點:成大資工系新館 **65304** 教室
主題:BFS
直播連結:https://youtube.com/live/QdZruoWnPZo?feature=share
:::
# 必作題題解
[TOC]
## 三章_第二節
### TOJ 432 - Akechi 明智的選擇
撰寫:fishhh
這裡改用 BFS 來解,就 BFS 的裸題
:::spoiler
```cpp=
#include<iostream>
using namespace std;
int move_x[]={0,0,-1,1},move_y[]={1,-1,0,0};
int a,b,n,m,map[1002][1002]={},u,v,f;
void bfs(int pos_x,int pos_y,int sum){
if(map[pos_x][pos_y]==-1){
return ;
}
if(map[pos_x][pos_y]==0){
map[pos_x][pos_y]=sum;
int nx,ny;
for(int i=0;i<4;i++){
nx=pos_x+move_x[i];
ny=pos_y+move_y[i];
if(nx<1||ny<1||nx>n||ny>m){
continue;
}
bfs(nx,ny,sum+1);
}
}
}
int main(){
int x,y;
cin>>n>>m>>x>>y>>u>>v>>f;
for(int i=0;i<f;i++){
cin>>a>>b;
map[a][b]=-1;
}
bfs(x,y,0);
if(map[u][v]==0){
cout<<"Harakiri!\n";
}
else{
cout<<"Cool!\n";
}
}
```
:::
---
### UVa 439 - Knight Moves
撰寫:fishhh
這裡比較不一樣的是處理騎士走路的問題。主要就是 dx 和 dy 陣列比較不同。
:::spoiler
```cpp=
#include "iostream"
#include "queue"
using namespace std;
int main(){
string x,y;
while(cin>>x>>y){
queue<pair<int,int>> q;
int ans[10][10]={};
bool vis[10][10]={};
int tar_x=y[0]-'a',tar_y=y[1]-'0';
tar_x++;
int np_x=x[0]-'a',np_y=x[1]-'0';
np_x++;
int cx[]={-2,-1,1,2,2,1,-1,-2},cy[]={-1,-2,2,1,-1,-2,2,1};
int nst=0;
q.push({np_x,np_y});
vis[np_x][np_y]=1;
ans[np_x][np_y]=0;
while(!q.empty()){
int nl=q.size();
for(int i=0;i<nl;i++){
auto np=q.front();
q.pop();
ans[np.first][np.second]=nst;
if(np.first==tar_x&&np.second==tar_y){
while(q.size())q.pop();
break;
}
for(int x=0;x<8;x++){
int nx=np.first+cx[x],ny=np.second+cy[x];
if(nx<=0||ny<=0||nx>=9||ny>=9)continue;
if(!vis[nx][ny]){
q.push({nx,ny});
vis[nx][ny]=1;
}
}
}
nst++;
}
printf("To get from %s to %s takes %d knight moves.\n",x.c_str(),y.c_str(),nst-1);
}
}
```
:::
---
### UVa 532 - Dungeon Master
撰寫:fishhh
這題比較不同的就是地圖變成3維了,其餘操作都相同。
可以練一下實作的能力~
:::spoiler
```cpp=
#include<queue>
#include<iostream>
using namespace std;
struct node{
int x;
int y;
int z;
};
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int l,r,c;
string str;
int map[40][40][40],el,er,ec;
while(cin>>l>>r>>c){
if(l==0&&r==0&&c==0){
return 0;
}
queue<node> q;
node tmp,now;
bool vis[40][40][40]={};
for(int il=0;il<l;il++){
for(int ir=0;ir<r;ir++){
cin>>str;
for(int ic=0;ic<c;ic++){
if(str[ic]=='#'){
map[ic][ir][il]=-1;
vis[ic][ir][il]=1;
}
else if(str[ic]=='.'){
map[ic][ir][il]=0;
}
else if(str[ic]=='S'){
map[ic][ir][il]=0;
tmp.x=ic;
tmp.y=ir;
tmp.z=il;
vis[ic][ir][il]=1;
q.push(tmp);
}
else{
map[ic][ir][il]=0;
el=il,er=ir,ec=ic;
}
}
}
}
//input end
int time=0,cx[]={0,0,-1,1},cy[]={-1,1,0,0};
while(!q.empty()){
int nl=q.size();
for(int inl=0;inl<nl;inl++){
node nxt;
now=q.front();
q.pop();
nxt=now;
if(map[now.x][now.y][now.z]==-1){
continue;
}
map[now.x][now.y][now.z]=time;
if(nxt.z-1>=0){
nxt.z--;
if(!vis[nxt.x][nxt.y][nxt.z]){
vis[nxt.x][nxt.y][nxt.z]=1;
q.push(nxt);
}
nxt.z++;
}
if(nxt.z+1<l){
nxt.z++;
if(!vis[nxt.x][nxt.y][nxt.z]){
vis[nxt.x][nxt.y][nxt.z]=1;
q.push(nxt);
}
nxt.z--;
}
for(int i=0;i<4;i++){
nxt.x=now.x+cx[i],nxt.y=now.y+cy[i],nxt.z=now.z;
if(nxt.x<0||nxt.y<0||nxt.x>=c||nxt.y>=r){
continue;
}
if(!vis[nxt.x][nxt.y][nxt.z]){
vis[nxt.x][nxt.y][nxt.z]=1;
q.push(nxt);
}
}
}
time++;
}
// for(int il=0;il<l;il++){
// for(int ir=0;ir<r;ir++){
// for(int ic=0;ic<c;ic++){
// cout<<map[ic][ir][il]<<" ";
// }
// cout<<"\n";
// }
// cout<<"\n";
// }
if(map[ec][er][el]!=0){
cout<<"Escaped in "<<map[ec][er][el]<<" minute(s).\n";
}
else{
cout<<"Trapped!\n";
}
}
}
```
:::
---
### UVa 10102 - The path in the colored field
撰寫:fishhh
一開始可能會想說,對於每一個 1 做 BFS 找最短路。
分析一下複雜度,做一次 BFS 的時間是 $O(n^2)$ 然後最多有可能做 $O(n^2)$ (因為最多有 $n^2$ 個 1)
整體就是 $O(n^4)$ 接近 $10^8$ 雖然常數不大 但很可能 TLE。
又有另一個想法,把所有 1 跟 3 的座標抓出來,然後對於每個 1 去掃過一次所有 3 的座標( x,y 座標差就是他們之間最短距離! ) 就可以知道對於一個 1 的位置與 3 的最短距離!
然後全部的 1 都做一次然後取最大值,就可以知道答案了~
分析複雜度,最壞的情況有 $(n^2)/2$ 個 1 有 $(n^2)/2$ 個 3 (這樣乘起來才會盡量大),所以複雜度會是 $O(n^4)$ 但嚴格來說這個會快一點點啦XD。
其實實際上還是跟找最短路徑一樣,反正就是把所有起點都 push 進 queue 裡面,然後做一次 BFS 就好~
:::spoiler
```cpp=
#include<bits/stdc++.h>
using namespace std;
struct Node {
int x, y, dis;
};
char board[110][110];
bool used[110][110];
Node q[2000000];
int m, dx[4]={0,1,0,-1}, dy[4]={1,0,-1,0};
int bfs(int start_y, int start_x) {
Node current, next;
memset(used, false, sizeof(used));
q[0].y = start_y;
q[0].x = start_x;
q[0].dis = 0;
for (int i = 0, j = 1; i < j; i++) {
current = q[i];
if (board[current.y][current.x] == '3') {
return current.dis;
} else {
for (int k = 0; k < 4; k++) {
next = current;
next.x += dx[k];
next.y += dy[k];
next.dis++;
if (next.x >= 0 && next.x < m && next.y >= 0 && next.y < m) {
if (!used[next.y][next.x]) {
used[next.y][next.x] = true;
q[j] = next;
j++;
}
}
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
while (cin >> m) {
vector<int> distances;
for (int i = 0; i < m; i++) {
for (int j = 0; j < m; j++) {
cin >> board[i][j];
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < m; j++) {
if (board[i][j] == '1') {
distances.push_back(bfs(i, j));
}
}
}
sort(distances.begin(), distances.end());
cout << distances.back() << "\n";
}
return 0;
}
```
:::
---