link
![](https://img2020.cnblogs.com/blog/1929461/202004/1929461-20200425222400683-903688326.png)
class Solution {
public:
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct Point{
int x;
int y;
};
int dis[105][105];
int m,n;
Point S,T;
int mcnt;
int ocnt;
vector<vector<int>> dp;
int minimalSteps(vector<string>& maze) {
vector<Point> ms;
vector<Point> os;
m=maze.size();
n=maze[0].size();
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(maze[i][j]=='M'){
ms.push_back(Point{i,j});
mcnt++;
}else if(maze[i][j]=='O'){
os.push_back(Point{i,j});
ocnt++;
}else if(maze[i][j]=='S'){
S=Point{i,j};
}else if(maze[i][j]=='T'){
T=Point{i,j};
}
}
}
vector<int> StoStone(ocnt,-1); // S to stone
int StoT=-1;
bfs(S,maze);
StoT=dis[T.x][T.y];
for(int i=0;i<ocnt;i++){
StoStone[i]=dis[os[i].x][os[i].y];
}
if(mcnt==0){
return StoT;
}
vector<int> TtoM(mcnt,-1); // T to M
bfs(T,maze);
for(int i=0;i<mcnt;i++){
TtoM[i]=dis[ms[i].x][ms[i].y];
}
vector<vector<int>> MtoStone(mcnt,vector<int>(ocnt,-1)); // M to stone
for(int i=0;i<mcnt;i++){
bfs(ms[i],maze);
for(int j=0;j<ocnt;j++){
MtoStone[i][j]=dis[os[j].x][os[j].y];
}
}
vector<vector<int>> MtoM(mcnt,vector<int>(mcnt,-1)); //M to M
for(int i=0;i<mcnt;i++){
for(int j=i+1;j<mcnt;j++){
for(int k=0;k<ocnt;k++){
if(MtoStone[i][k]==-1 || MtoStone[j][k]==-1) continue;
if(MtoM[i][j]==-1) MtoM[i][j]=MtoStone[i][k]+MtoStone[j][k];
else if(MtoStone[i][k]+MtoStone[j][k]<MtoM[i][j]) MtoM[i][j]=MtoStone[i][k]+MtoStone[j][k];
}
MtoM[j][i]=MtoM[i][j];
}
}
vector<int> StoM(mcnt,-1); // S to M
for(int i=0;i<mcnt;i++){
for(int j=0;j<ocnt;j++){
if(StoStone[j]==-1 || MtoStone[i][j]==-1) continue;
if(StoM[i]==-1) StoM[i]=StoStone[j]+MtoStone[i][j];
else if(StoStone[j]+MtoStone[i][j]<StoM[i]) StoM[i]=StoStone[j]+MtoStone[i][j];
}
}
int all=(1<<mcnt)-1;
dp=vector<vector<int>>(mcnt,vector<int>(all,-2));
int res=INT_MAX;
for(int i=0;i<mcnt;i++){
int tmp=StoM[i];
if(tmp==-1) continue;
int next=dfs(i,all^(1<<i),TtoM,MtoM);
if(next!=-1){
res=min(res,tmp+next);
}
}
return res==INT_MAX?-1:res;
}
int dfs(int cur, int state, vector<int> &TtoM,vector<vector<int>>& MtoM){
if(state==0){
return TtoM[cur];
}
if(dp[cur][state]!=-2) return dp[cur][state];
int ret=-1;
for(int i=0;i<mcnt;i++){
if((state&(1<<i))==0 || MtoM[cur][i]==-1) continue;
int tmp=MtoM[cur][i];
int next=dfs(i,state^(1<<i),TtoM,MtoM);
if(next==-1) continue;
if(ret==-1) ret=tmp+next;
else ret=min(ret,tmp+next);
}
return dp[cur][state]= ret;
}
void bfs(Point start, vector<string>& maze){
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
dis[i][j]=-1;
}
}
dis[start.x][start.y]=0;
queue<Point> q;
q.push(start);
vector<vector<int>> visited(m,vector<int>(n));
visited[start.x][start.y]=1;
while(!q.empty()){
auto cur=q.front();
q.pop();
for(int d=0;d<4;d++){
int nx=cur.x+dir[d][0];
int ny=cur.y+dir[d][1];
if(nx<0 || nx>=m || ny<0 || ny>=n || maze[nx][ny]=='#' || visited[nx][ny]==1) continue;
visited[nx][ny]=1;
dis[nx][ny]=1+dis[cur.x][cur.y];
q.push(Point{nx,ny});
}
}
}
};