1140 : Cleaning Robot
幅優先探索 + ビットDP
汚れたマスを都市とした巡回セールスマン問題と見なせる。(ただしスタート地点に戻る必要はない)
事前に汚れたマス同士の距離を幅優先探索で計算し、あとはビットDPで計算。
int w,h; int dx[] = {1,0,-1,0}; int dy[] = {0,1,0,-1}; //p1->p2 の最短距離 int calc(vector<string> grid, P p1, P p2){ int used[20][20]; memset(used, -1, sizeof(used)); queue<P> que; que.push(p1); used[p1.first][p1.second] = 0; while(!que.empty()){ P st = que.front(); que.pop(); if(st == p2) return used[st.first][st.second]; REP(r,4){ int cost = used[st.first][st.second]; int ny = st.first + dy[r]; int nx = st.second + dx[r];; if(0<=ny && ny<h && 0<=nx && nx<w){ if(used[ny][nx] == -1 && grid[ny][nx] != 'x'){ used[ny][nx] = cost + 1; que.push(P(ny,nx)); } } } } return INF; } int main(){ while(cin>>w>>h,w){ vector<string> grid(h); REP(i,h)cin>>grid[i]; P start; //初期位置 vector<P> target; //汚れたマス REP(y,h)REP(x,w){ if(grid[y][x]=='o'){ start = P(y,x); }else if(grid[y][x] == '*'){ target.push_back(P(y,x)); } } int n = target.size(); int d[10][10] = {}; //d[i][j]: target[i]とtarget[j]の距離 REP(i,n)REP(j,n){ d[i][j] = (i!=j)?(calc(grid,target[i],target[j])):0; } //dp[S][i] 最短距離: iは最後に到達したマス。Sは到達済みマスをbitであらわす。 int dp[1<<10][10]; REP(i,1<<n)REP(j,n)dp[i][j] = INF; //startからtarget[i]までの移動を最初に行う REP(i,n)dp[1<<i][i] = calc(grid, start, target[i]); REP(s,1<<n)REP(from,n){ REP(to,n){ dp[s|1<<to][to] = min(dp[s|1<<to][to], dp[s][from] + d[from][to]); } } int ans = INF; REP(i,n)ans = min(ans, dp[(1<<n)-1][i]); if(ans == INF) ans = -1; cout<<ans<<endl; } return 0; }