Problem 1140 : Cleaning Robot

keyword

最短経路 BFS BruteForce C++

概要

地図とゴミの位置とロボットの初期位置が与えられる。ロボットがゴミを拾うのに最短で歩く距離を求める問題。ゴミの位置は10以下。地図は20*20以下。
前処理として各ゴミと初期位置間の距離をBFSとかで計算しておけば後は10!通り全探索すればよい。ただしこの方法だとAOJでは通ったがPKUではTLE。一応座標を一つのintで持つとか細かい最適化はしたのですが、それ以上の枝刈りなどが必要かもしれません。

int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};

inline int PtoN(int x, int y){
    return 20*x + y;
}

int main(){
    int w, h, i, j, d, st, best, dd, cur;
    string line;
    while(scanf("%d%d\n",&w,&h)){
        if(!(w||h)) break;
        vector<string> board;
        vector< vector<int> > dist(400, vector<int>(400,1<<21));
        vector<int> ds;
        d = 0;
        REP(i,h){
            getline(cin,line);
            board.PB(line);
        }
        REP(i,h)REP(j,w){
            if(board[i][j]=='*'){
                d++;
                ds.PB(PtoN(j,i));
            }
            else if(board[i][j]=='o'){
                st = PtoN(j,i);
            }
        }
        sort(ALL(ds));
        ds.PB(st);
        REP(i,d+1){
            queue<int> Q;
            Q.push(1000*ds[i] + 0);
            while(!Q.empty()){
                int tp=Q.front();
                int cd = tp/1000, cx=cd/20, cy=cd%20, dss=tp%1000;
                REP(j,4){
                    int x=cx+dx[j], y=cy+dy[j];
                    if(0<=x && x<w && 0<=y && y<h &&
                            board[y][x]!='x' &&
                            dist[ds[i]][PtoN(x,y)]>(1<<20)){
                        Q.push(1000*PtoN(x,y)+dss+1);
                        dist[ds[i]][PtoN(x,y)] = dss+1;
                    }
                }
                Q.pop();
            }
        }
        ds.pop_back();
        best = 1<<21;
        do{
            dd = dist[st][ds[0]];
            REP(i,d-1){
                dd += dist[ds[i]][ds[i+1]];
                if(dd >= best) goto end;
            }
            best = dd;
end:;
        }while(next_permutation(ALL(ds)));
        printf("%d\n",(best>(1<<20))?-1:best);
    }
    return 0;
}