* 2차원이 안되는 이유
- 처음설계
- 상태 : (y, x , 그때 벽부순 count)를 두고 bfs를 돌리기
- if(next_cnt >= 2) continue;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct A {
int y;
int x;
int cnt; // 여기좌표에 올때까지 부신 벽의갯수
A(int y, int x, int cnt) : y(y), x(x), cnt(cnt) {};
};
int n, m, arr[1004][1004], vis[1004][1004];
int dy[] = { 1,0,-1,0 };
int dx[] = { 0,1,0,-1 };
ll ret; //배정된 예산중 최대값
queue<A> q;
int main()
{
cin >> n>>m;
for (int i = 0; i < n; ++i) {
string tmp = "";
cin >> tmp;
for (int j = 0; j < m; ++j) {
arr[i][j] = tmp[j]-'0';
}
}
/*for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cout << arr[i][j];
}cout << "\n";
}*/
vis[0][0] = 1;
q.push(A(0,0,0));
while (q.size()) {
int y = q.front().y;
int x = q.front().x;
int cnt = q.front().cnt;
//cout << y << " " << x << " " << cnt << "\n";
q.pop();
for (int i = 0; i < 4; ++i) {
int ny = y + dy[i];
int nx = x + dx[i];
int nc = cnt;
if (ny >= n || ny < 0 || nx >= m || nx < 0) continue;
if (vis[ny][nx]) continue;
if (arr[ny][nx] == 1) nc++;
if (nc >= 2) continue;
q.push(A(ny,nx, nc));
vis[ny][nx] = vis[y][x] + 1;
}
}
/*cout << "\n";
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cout << vis[i][j];
}cout << "\n";
}*/
if (vis[n - 1][m - 1] == 0) {
cout << -1;
return 0;
}
cout << vis[n - 1][m - 1];
return 0;
}
- 반례
- 1번경로는 벽은 부수지않는상태이다.
- 2번경로는 벽하나를 부수는 상태이다.
- 벽을 부수는 상태가 벽은 부수지않는 상태에 영향을 준다.
- 1번의 상태는 벽을 하나도 안부순상태
- 2번은 벽을 하나깨고 온 상태
- 이를 격리해야한다.
- 즉, 매 좌표마다 벽을 깻는지 안깻는지 기록하고 구분해야 한다.
* 해결방안 : 상태추가
- 벽을 꺳는지 안깻는지 상태를 추가하면된다.
- vis [ y ] [x] [crashed]
- 큐에도 똑같은 상태를 넣어준다.
- 아래와 같이 상태를 완전히 분리한다. (vis)
- crashed=1인 상태에서는 1을 만난경우, 진행을 못한다.
- crashed=0인 상태에서는 1을 만난경우, 상태를 바꾼다(옆세계로 넘어감)
- 키포인트 : crashed=0에서 crashed=1 쪽으로만 넘어갈수 있음!!! (by 문제조건)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//상태정의 : (y, x, 벽부쉇는지)
struct A {
int y;
int x;
int crashed; // 현재 상태일때 벽부쉇는지
A(int y, int x, int crashed) : y(y), x(x), crashed(crashed) {};
};
int n, m, arr[1004][1004], vis[1004][1004][2];
int dy[] = { 1,0,-1,0 };
int dx[] = { 0,1,0,-1 };
ll ret; //배정된 예산중 최대값
queue<A> q;
int main()
{
cin >> n>>m;
for (int i = 0; i < n; ++i) {
string tmp = "";
cin >> tmp;
for (int j = 0; j < m; ++j) {
arr[i][j] = tmp[j]-'0';
}
}
/*for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cout << arr[i][j];
}cout << "\n";
}*/
int ok = 0; //갈수있는지
vis[0][0][0] = 1;
q.push(A(0,0,0));
while (q.size()) {
int y = q.front().y;
int x = q.front().x;
int crashed = q.front().crashed;
//cout << y << " " << x << " " << crashed << "\n";
q.pop();
//탈출은 pop 다음에
if (y == n - 1 && x == m-1) {
ok = 1;
ret= vis[y][x][crashed];
break;
}
for (int i = 0; i < 4; ++i) {
int ny = y + dy[i];
int nx = x + dx[i];
if (ny >= n || ny < 0 || nx >= m || nx < 0) continue;
if (vis[ny][nx][crashed]) continue;
//next가 벽이 아닌경우, 그냥 bfs와 동일논리
if (arr[ny][nx] == 0) {
vis[ny][nx][crashed] = vis[y][x][crashed] + 1;
q.push(A(ny, nx, crashed));
}
else { //next가 벽인경우
if (crashed == 1) continue; //이미 부셧다면 불가.
//안부신경우(crashed==0), 다음상태는 부순걸로표시
vis[ny][nx][crashed+1] = vis[y][x][crashed] + 1;
q.push(A(ny, nx, crashed+1));
}
}
}
if (ok) {
cout << ret;
}
else
cout << -1;
//cout << "\n";
//for (int i = 0; i < n; ++i) {
// for (int j = 0; j < m; ++j) {
// cout << vis[i][j]<< " ";
// }cout << "\n";
//}
//if (vis[n - 1][m - 1] == 0) {
// cout << -1;
// return 0;
//}
//cout << vis[n - 1][m - 1];
return 0;
}
* 행동영역
- 최단거리는 bfs
- 조건이 추가되면, 상태로 나타낸다.
- 각각의 상태를 분리시키고 설계한다.
- 상태를 vis, queue에 넣는다.
- 탈출조건을 pop 직후에두고, flag를 둬서 못가는경우를 고려한다.
- struct 사용법 암기.
struct A{
int a,b,c;
A(int a, int b, int c) : a(a), b(b), c(c) {}
}
//사용시
A a = A(1,2,3)
'Algorithm > bfs' 카테고리의 다른 글
[알고리즘] 리트코드 116. 각 노드의 다음 오른쪽 포인터 채우기 c++ // bfs 트리순회 (0) | 2024.07.01 |
---|---|
백준 16928 뱀과 사다리 게임 c++ // dp불가능한경우, bfs복습 (0) | 2024.05.13 |
백준 9205 맥주마시면서걸어가기 c++ // bfs, 출력시 "\n을 빼먹지마라.." (0) | 2024.03.09 |
백준 5014 스타트링크 c++ // bfs 를 사용하라. (dfs는 시간초과) (0) | 2024.03.04 |
백준 13549 숨바꼭질3 c++ // pq를 이용한 bfs 구현방법 (0) | 2023.11.29 |