• 【经典】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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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;
           
       }
    };
  • 相关阅读:
    Windows7旗舰版安装VS2008的SP1的问题(KB945140, KB947888)
    Hex RGB颜色值互换
    php沥遍目录结构
    linux ftp设置
    Android开发环境搭建
    php读取excel文件
    wordpress插件制作
    wordpress主题制作
    php读取excel文件(OLERead.php页代码)
    php ios推送
  • 原文地址:https://www.cnblogs.com/zsben991126/p/13154454.html
Copyright © 2020-2023  润新知