寻宝

在这里插入图片描述

思路分析:
首先如果有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;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值