2차원 평면에서 S부터 2개의 C블럭을 모두 도달하는 최단 거리 BFS인데 조건이 있다.
같은 방향으로 2번 이상 이동할 수가 없다.
원래 BFS를 할때 visit[N][M] 처럼 했다면, "어디쪽에서 왔는가"도 추가해야한다.
그리고 2개의 C블럭을 모두 도달해야 한다. 이것을 C0, C1 으로 부른다면 어떤 지점까지 움직였을 때, 문제를 얼만큼 해결했는 가를 4가지 상태로 나타낼 수 있다.
1. C0, C1 을 모두 못 찾았다.
2. C0 을 찾았다
3. C1 을 찾았다.
4. C0, C1 을 모두 찾았다.
(C0를 찾았다, C1를 찾았다) 로 표현한다면 00, 10, 01, 11 로 나타낼 수 있고, 이를 2진수로 본다면 10진수 0, 2, 1, 3 이다.
4번의 상태가 나올때까지, 같은 방향으로 진행하지 않으면서, 이전에 왔던 위치에 이전과 똑같은 움직임으로 다시 방문하지 않고 (visit[y][x][previousDirect]), 그 때의 '얼만큼 찾았는 가'의 상태마저 같지 않은 경우만 탐색하면 된다.
#include <bits/stdc++.h> using namespace std; #define INF 987654321 const int DX[]={-1, 0, 1, 0}; const int DY[]={ 0,-1, 0, 1}; struct gift { int y, x, t; char prevDirect; char cBit; }; int main(){ int i, j, d, h, w; scanf("%d %d ", &h, &w); char s[51][51]={}; for(i=0; i<h; ++i) scanf("%s ", s[i]); int cost[51][51][4][4]; int startX=-1, startY=-1, totalC = 0; int cx[2], cy[2]; for(i=0; i<h; ++i){ for(j=0; j<w; ++j){ if(s[i][j]=='S'){ startX = j; startY = i; } if(s[i][j]=='C'){ cx[totalC] = j; cy[totalC++] = i; } } } for(i=0; i<51; ++i){ for(j=0; j<51; ++j){ for(d=0; d<16; ++d) cost[i][j][d/4][d%4] = INF; } } queue<gift> q; q.push({startY, startX, 0, -1, 0}); int minCost = INF; while(!q.empty()){ gift cur = q.front(); q.pop(); if(cur.cBit == 3){ minCost = min(minCost, cur.t); continue; } for(i=0; i<4; ++i){ if(i == cur.prevDirect) continue; int dy = cur.y+DY[i], dx = cur.x+DX[i]; if(dy < 0 || dx < 0 || dy >= h || dx >= w || s[dy][dx] == '#' || cur.t+1 >= cost[dy][dx][i][cur.cBit]) continue; if((cur.cBit&1)==1 && cx[0]==dx && cy[0]==dy ) continue; if((cur.cBit&2)==2 && cx[1]==dx && cy[1]==dy ) continue; q.push({dy, dx, cur.t+1, i, cur.cBit | ((cx[1]==dx&&cy[1]==dy)<<1) | (cx[0]==dx&&cy[0]==dy)}); cost[dy][dx][i][cur.cBit] = cur.t+1; } } printf("%d", minCost<INF?minCost:-1); return 0; }
댓글 없음:
댓글 쓰기