1218 - Push!!

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1218

問題

図見れば分かる。
貨物を何回動かせばゴールに到達できるか。

解法

状態は人の座標と貨物の座標。
見た瞬間普通のBFSかと思って書いてWA。
人が動くのはコスト0だから、グラフで言えばコスト0の辺とコスト1の辺が混在してるグラフでの最短路。
よってpriority_queueを使ってダイクストラっぽくすればいい。
コスト1の辺だけだからこそBFSで最短コストを求められるというのを理解した。


それにしても、配列[y][x]ではなく配列[x][y]とする癖そろそろ直さないと・・・。

ソース

struct P {
  int x,y,cx,cy;
  int cost;
  P(int x,int y,int cx,int cy,int cost) : x(x),y(y),cx(cx),cy(cy),cost(cost) {}
};
const bool operator<(const P &a, const P &b) {
  return a.cost > b.cost;
}

bool visited[7][7][7][7];
int main() {
  int w,h;
  while(cin>>w>>h,w||h) {
    int ba[w][h];
    int sx,sy,cx,cy;
    REP(y,h) {
      REP(x,w) {
        cin >> ba[x][y];
        if (ba[x][y] == 4) {
          sx = x; sy = y;
        } else if (ba[x][y] == 2) {
          cx = x; cy = y;
        }
      }
    }
    priority_queue<P> Q;
    Q.push(P(sx,sy,cx,cy,0));
    memset(visited,0,sizeof(visited));
    const int dx[] = {-1,0,1,0};
    const int dy[] = {0,1,0,-1};
    int res = -1;
    while(!Q.empty()) {
      P now = Q.top(); Q.pop();
      int x=now.x,y=now.y,cx=now.cx,cy=now.cy,cost=now.cost;
      if (visited[x][y][cx][cy]) continue;
      visited[x][y][cx][cy] = 1;
      
      if (ba[cx][cy] == 3) {
        res = cost;
        break;
      }
      REP(k,4) {
        int xx = x+dx[k];
        int yy = y+dy[k];
        if (xx<0||xx>=w||yy<0||yy>=h) continue;
        if (ba[xx][yy] == 1) continue;
        if (xx==cx&&yy==cy) {
          // push
          int xxx = cx+dx[k];
          int yyy = cy+dy[k];
          if (xxx<0||xxx>=w||yyy<0||yyy>=h) continue;
          if (ba[xxx][yyy] == 1 || visited[x][y][xxx][yyy]) continue;
          Q.push(P(x,y,xxx,yyy,cost+1));
        } else {
          if (visited[xx][yy][cx][cy]) continue;
          // move;
          Q.push(P(xx,yy,cx,cy,cost));
        }
      }
    }
    cout << res << endl;
  }
}