【经典】bfs+建图+TSP状压dp——leetcode 寻宝

 这道题dp部分不难,就是建模和写起来麻烦。。

首先分析给定的地图,我们可以发现只有那些石堆,起点,终点,机关所在地是有用的(不超过100)个点的信息是有用的

再进行分析,可以以将起点终点机关当做点,石堆当做边来建图

然后我们就可以在无向图上进行dp

  经典的tsp问题,dp[S][i]表示访问的点集状态为S,当前在第i个点时的最少代价,

  dp[S][i]转移到dp[S|1<<j][j]时,我们要枚举从i到j,用的是哪一个石堆的石头,当然就是到i,j的距离和最小的那个石堆,这里可以预处理获得

 

struct Point{
   int x;
   int y;
   
   void print(){
       printf("%d %d\n", x, y);
   }
};

class Solution {
public:
   
   static const int maxn = 102;
   
   int dist[maxn][maxn], vis[maxn][maxn];
   Point q[maxn * maxn], S, T, puzzle[20], stone[50];
   
   int distS[50], distT[50], distM[20][50], distBM[20][20];
   
   int dp[1 << 16][16];
   
   int dx[4] = {1,0,-1,0};
   int dy[4] = {0,1,0,-1};
   
   void BFS(vector<string>& maze, int &n, int &m, Point start){
       int front, rear;
       memset(vis, 0, sizeof(vis));
       memset(dist, -1, sizeof(dist));
       
       front = rear = 1;
       
       dist[start.x][start.y] = 0;
       vis[start.x][start.y] = 1;
       q[rear++] = start;
       
       while(front != rear){
           Point i = q[front++];
           int nowx = i.x, nowy = i.y;
           
           for(int dir = 0; dir < 4; ++dir){
               int newx = i.x + dx[dir], newy = i.y + dy[dir];
               
               if(newx >= 0 && newx < n && newy >= 0 && newy < m){
                   if(maze[newx][newy] != '#' && !vis[newx][newy]){
                       dist[newx][newy] = dist[nowx][nowy] + 1;
                       q[rear++] = (Point){newx, newy};
                       vis[newx][newy] = 1;
                       
                   }
               }
           }
       }
   }
   
   int minimalSteps(vector<string>& maze) {
       int n = maze.size(), m = maze[0].size();
       
       int curp, curs;
       curp = curs = 0;
       for(int i = 0; i < n; ++i)
           for(int j = 0; j < m; ++j){
               if(maze[i][j] == 'S')S = (Point){i, j};
               if(maze[i][j] == 'T')T = (Point){i, j};
               if(maze[i][j] == 'M')puzzle[curp++] = (Point){i, j};
               if(maze[i][j] == 'O')stone[curs++] = (Point){i, j};
           }
       
       memset(distS, -1, sizeof(distS));
       memset(distT, -1, sizeof(distT));
       memset(distM, -1, sizeof(distM));
       
       BFS(maze, n, m, S);
       
       if(curp == 0)return dist[T.x][T.y];
       
       for(int i = 0; i < curs; ++i){
           Point &sto = stone[i]; 
           distS[i] = dist[sto.x][sto.y];
           //printf("%d %d\n", i, distS[i]);
       }
       
       BFS(maze, n, m, T);
       
       for(int i = 0; i < curp; ++i){
           Point &puz = puzzle[i];
           distT[i] = dist[puz.x][puz.y];
           //printf("%d %d\n", i, distT[i]);
       }
       
       for(int i = 0; i < curp; ++i){
           Point puz = puzzle[i];
           BFS(maze, n, m, puz);
           for(int j = 0; j < curs; ++j){
               Point sto = stone[j]; 
               distM[i][j] = dist[sto.x][sto.y];
           }
       }
       
       
       memset(dp, -1, sizeof(dp));
       


       for(int i = 0; i < curp; i++){
           int idx = 1 << i, best = -1;
           for(int j = 0; j < curs; j++){
               if(distS[j] != -1 && distM[i][j] != -1){
                   int curDist = distS[j] + distM[i][j];
                   if(best == -1 || curDist < best)best = curDist;
               }
           }
           
           dp[idx][i] = best;
           
           //printf("%d %d %d\n", idx, i, best);
       }
       
       int ALL = 1 << curp;
       
       for(int i = 0; i < curp; ++i)
           for(int j = 0; j < curp; ++j){
               if(i == j)distBM[i][j] = 0;
               else{
                   distBM[i][j] = -1;
                   for(int k = 0; k < curs; ++k ){
                       if(distM[i][k] != -1 && distM[j][k] != -1){
                           int cur = distM[i][k] + distM[j][k];
                           if(distBM[i][j] == -1 || cur < distBM[i][j])
                               distBM[i][j] = cur;
                       }
                   }
               }
           }
       
       
       for(int i = 1; i < ALL; ++i){
           for(int j = 0; j < curp; ++j){
               if(i & (1 << j)){
                   for(int k = 0; k < curp; ++k){
                       if(j != k && (i & (1 << k)) && dp[i - (1 << j)][k] != -1 && distBM[k][j] != -1){
                           
                           int cur = dp[i - (1 << j)][k] + distBM[k][j];
                           //printf("%d %d %d %d\n", i, j, k, cur);
                           
                           if(dp[i][j] == -1 || cur < dp[i][j])dp[i][j] = cur;
                       }
                   }
               }
           }
       }
       
       
       int ans = -1;
       for(int i = 0; i < curp; ++i){
           if(dp[ALL - 1][i] != -1 && distT[i] != -1){
               int cur = dp[ALL - 1][i] + distT[i];
               if(ans == -1 || cur < ans)ans = cur;
           }
       }

       
       return ans;
       
   }
};

 

上一篇:设计模式——Factory Method


下一篇:Phillip and Trains(bfs)