思路分析:
首先如果有M存在的话:最短路径一定是:S-O-M-O-M-…-T
当没有M存在的话,即S-T的最短路径,可以BFS来S-T的最短距离
当没有M存在的话,考虑最简单的情况,即不需要搬石头的情况,就是状压dp类似最短哈曼顿路径来求经S-T的最短距离,即首先DFS求出每个M到达其他M即起点终点的距离,dp[i][j]表示当前到达的点情况为i处于j点的情况,状压dp求解。
再考虑更复杂的需要取石块的情况,即需要加一步(每个石块堆到达每个M点的距离),这样求出后我们可以预处理出两个M点之间的最短距离,这里吧起点也当作一个M点,由于到达终点前不需要去取石头,故我们把终点分离出来,用状压求解出到达全面M点后的情况,再加上最后一个M点到达终点的距离即可。
class Solution {
public:
int sx,sy,ex,ey,n,m,cnt,ans;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
struct Node{
int x;
int y;
int val;
Node(){}
Node(int a,int b,int c){
x=a;
y=b;
val=c;
}
}a[20];
int dist[105][105];
int def[105][105];
bool vis[105][105];
int stone[105][105];
int jige[50][20];
bool Judge(vector<string>& maze,int k){
int f=1,v=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
vis[i][j]=0;
}
}
dist[k][k]=0;
queue<Node> p;
int minz=10000;
p.push(Node(a[k].x,a[k].y,0));
vis[a[k].x][a[k].y]=1;
while(p.size()){
Node temp=p.front();
p.pop();
int x=temp.x;
int y=temp.y;
int val=temp.val;
for(int i=0;i<4;i++){
int ix=x+dx[i];
int iy=y+dy[i];
if(ix>=0&&ix<n&&iy>=0&&iy<m&&!vis[ix][iy]){
if(maze[ix][iy]=='.'){
p.push(Node(ix,iy,val+1));
vis[ix][iy]=1;
}
else if(maze[ix][iy]=='O'){
minz=min(minz,val+1);
int h=stone[ix][iy];
jige[h][k]=min(jige[h][k],val+1);
p.push(Node(ix,iy,val+1));
vis[ix][iy]=1;
++v;
if(v>=ans&&f>=cnt) return true;
}
else if(maze[ix][iy]=='M'||maze[ix][iy]=='T'||maze[ix][iy]=='S'){
p.push(Node(ix,iy,val+1));
++f;
vis[ix][iy]=1;
int h=def[ix][iy];
dist[k][h]=min(dist[k][h],val+1);
if(v>=ans&&f>=cnt) return true;
}
}
}
}
for(int i=0;i<cnt;i++){
if(dist[k][i]==10000) return false;
}
if(minz==10000&&cnt>2) return false;
a[k].val=minz;
return true;
}
int minimalSteps(vector<string>& maze) {
n=maze.size();
m=maze[0].size();
memset(def,-1,sizeof(def));
memset(stone,-1,sizeof(stone));
memset(jige,0x3f,sizeof(jige));
cnt=1;
ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(maze[i][j]=='S'){
sx=i;
sy=j;
}
else if(maze[i][j]=='O'){
stone[i][j]=ans;
ans++;
}
else if(maze[i][j]=='T'){
ex=i;
ey=j;
}
else if(maze[i][j]=='M'){
a[cnt].x=i;
a[cnt].y=j;
def[i][j]=cnt;
cnt++;
}
}
}
a[0].x=sx;
a[0].y=sy;
def[sx][sy]=0;
a[cnt].x=ex;
a[cnt].y=ey;
def[ex][ey]=cnt;
cnt++;
for(int i=0;i<=cnt;i++){
for(int j=0;j<=cnt;j++){
dist[i][j]=10000;
}
}
if(!Judge(maze,cnt-1)) return -1;
long long sum=1e9;
if(cnt==2){
return dist[cnt-1][0];
}
for(int i=0;i<cnt-1;i++){
if(!Judge(maze,i)) return -1;
}
vector<vector<int>> MM(20,vector<int>(20,10000));
for(int i=0;i<cnt-1;i++){
for(int j=0;j<cnt-1;j++){
if(i==j) MM[i][j]=1;
else{
for(int k=0;k<ans;k++){
MM[i][j]=min(MM[i][j],jige[k][i]+jige[k][j]);
}
}
}
}
vector<vector<long long>> dp((1<<(cnt-1))+10,vector<long long>(cnt+2,1e9));
dp[1][0]=0;
for(int i=0;i<(1<<(cnt-1));i++){
for(int j=0;j<cnt-1;j++){
if((i>>j)&1){
for(int k=0;k<cnt-1;k++){
if(((i-(1<<j))>>k)&1)
{
dp[i][j]=min(dp[i][j],dp[i-(1<<j)][k]+MM[k][j]);
}
}
}
}
}
for(int i=1;i<cnt-1;i++){
sum=min(sum,dp[(1<<cnt-1)-1][i]+dist[cnt-1][i]);
}
return sum;
}
};