SRM-425 500pt: PiecesMover
問題概要
サイズ5*5のボードが与えられ、そのうちN(<=5)マスには荷物が置いてある。全ての荷物を連結させるとき、最小で何回の移動が必要か求める問題。
解法
全状態が(25,5)通りしかないので探索が間に合う。書くだけ。
感想
最初はN(<5)の条件を見落としていたので最大ケース(25,13)だと思っていた。以下のソースでビット演算使っているのはその名残りだけど、N<=5でないと25倍が響いてどうせTLEするとおもう。ちなみに、N<=5という条件は非常に緩いので、多分ビット演算なんて細かいことはせずに2次元のvector突っ込んでも間に合うと思う。あと相変わらず実装が遅すぎる。
int dx[] = {0,0,1,-1}; int dy[] = {1,-1,0,0}; int N, C; int brd[5][5]; int getMinimumMoves(vector <string> board) { set<int> visited; int i, j, bit=0, k; N = 0; REP(i,5)REP(j,5)if(board[i][j] == '*'){ N++; bit |= 1<<(i*5+j); } visited.insert(bit); queue< pair<int,int> > Q; Q.push( MP(bit, 0) ); while(!Q.empty()){ bit = Q.front().first; int d = Q.front().second; Q.pop(); if(isConnect(bit)){ return d; } REP(i,5)REP(j,5)if((bit>>(i*5+j))&1){ int t = bit; REP(k,4){ t = bit^(1<<(i*5+j)); int ny = i+dy[k], nx = j + dx[k]; if(0<=ny&&ny<5 && 0<=nx&&nx<5 && !((t>>(ny*5+nx))&1)){ t ^= 1<<(ny*5+nx); if(visited.find(t) == visited.end()){ visited.insert(t); Q.push( MP(t, d+1) ); } } } } } return -1; } inline bool isConnect(int bbit){ int i, j; REP(i,5)REP(j,5)brd[i][j] = ((bbit>>(i*5+j))&1)?1:0; C = 0; REP(i,5)REP(j,5)if(brd[i][j]==1){ dfs(i,j); return C == N; } } inline void dfs(int y, int x){ int k; C++; brd[y][x] = 0; REP(k,4){ int ny = y + dy[k], nx = x + dx[k]; if(0<=ny&&ny<5&&0<=nx&&nx<5 && brd[ny][nx]) dfs(ny,nx); } }