这道题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; } };