• LCP 13. 寻宝


    题意

    我们得到了一副藏宝图,藏宝图显示,在一个迷宫中存在着未被世人发现的宝藏。

    迷宫是一个二维矩阵,用一个字符串数组表示。它标识了唯一的入口(用 'S' 表示),和唯一的宝藏地点(用 'T' 表示)。但是,宝藏被一些隐蔽的机关保护了起来。在地图上有若干个机关点(用 'M' 表示),只有所有机关均被触发,才可以拿到宝藏。

    要保持机关的触发,需要把一个重石放在上面。迷宫中有若干个石堆(用 'O' 表示),每个石堆都有无限个足够触发机关的重石。但是由于石头太重,我们一次只能搬一个石头到指定地点。

    迷宫中同样有一些墙壁(用 '#' 表示),我们不能走入墙壁。剩余的都是可随意通行的点(用 '.' 表示)。石堆、机关、起点和终点(无论是否能拿到宝藏)也是可以通行的。

    我们每步可以选择向上/向下/向左/向右移动一格,并且不能移出迷宫。搬起石头和放下石头不算步数。那么,从起点开始,我们最少需要多少步才能最后拿到宝藏呢?如果无法拿到宝藏,返回 -1 。
    题目链接:https://leetcode-cn.com/problems/xun-bao/

    解题思路

    从S走到T的条件是所有的M必须全部走完,那么我们只需要预处理出从S到任意M,从M到任意M的,从M到T的符合题意的最短路径即可。由于第一步一定是从S到O,第二步是从O到M;第三步是从M到O或者M到T,那么我们可以先通过Bfs算出从S到O,从O到M,从M到T的最短路径。在根据floylad算法计算出从M经过O达到M的最短路径即可。
    在预处理操作后,我们可以通过求哈密顿路径得到从S出发经过所有M达到T的最短路径。

    代码

    struct Point{
            int x,y;
        };
        bool vis[110][110];
        int dist[110][110];
        int distS[50],distT[50],distM[50][50],distMM[20][20];
        int dp[65540][20];
        int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
        const int INF=0x3f3f3f3f; //数会很大
        //返回从st出发到maze中其余各点的最短距离
        void Bfs(Point st,int m,int n,vector<string>& maze)
        {
            queue<Point>q;
            memset(dist,INF,sizeof(dist));
            memset(vis,0,sizeof(vis));
            vis[st.x][st.y]=1;
            dist[st.x][st.y]=0;
            q.push(st);
            while(!q.empty())
            {   
                Point t=q.front();
                q.pop();
                int x=t.x,y=t.y;
                for(int i=0;i<4;i++)
                {
                    int xx=x+dx[i],yy=y+dy[i];
                    if(xx>=0&&xx<m&&yy>=0&&yy<n&&maze[xx][yy]!='#'&&!vis[xx][yy]){
                        dist[xx][yy]=dist[x][y]+1;
                        q.push((Point){xx,yy});
                        vis[xx][yy]=1;
                    }
                }
            }
        }
    int minimalSteps(vector<string>& maze) {
            int m=maze.size(),n=maze[0].size();
            Point S,T,puzzle[16*16],stone[16*16];
            int p=0,s=0;
            for(int i=0;i<m;i++)
            {
                for(int j=0;j<n;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[p++]=(Point){i,j};
                    if(maze[i][j]=='O') stone[s++]=(Point){i,j};
                }
            }
            Bfs(S,m,n,maze);
            if(p==0) return dist[T.x][T.y]==INF?-1:dist[T.x][T.y];
            //从S到O的距离
            memset(distT,INF,sizeof(distT));
            memset(distS,INF,sizeof(distS));
            memset(distM,INF,sizeof(distM));
            memset(distMM,INF,sizeof(distMM));
            memset(dp,INF,sizeof(dp));
            for(int i=0;i<s;i++)
                distS[i]=dist[stone[i].x][stone[i].y];
            Bfs(T,m,n,maze);
            //从T到M的距离
            for(int i=0;i<p;i++)
                distT[i]=dist[puzzle[i].x][puzzle[i].y];
            for(int i=0;i<p;i++)
            {
                //cout<<puzzle[i].x<<" "<<puzzle[i].y<<endl;
                Bfs(puzzle[i],m,n,maze);
                for(int j=0;j<s;j++){
                    //cout<<dist[stone[i].x][stone[i].y]<<"  sss"<<endl;
                    distM[i][j]=dist[stone[j].x][stone[j].y];
                }
                    
            }
            //初始化dp数组,从S经过O达到各个M的距离 dp[mask][i] 
            for(int i=0;i<p;i++)
            {
                int index=(1<<i),tp=1e9+7;
                for(int j=0;j<s;j++){
                    if(tp>distS[j]+distM[i][j]) tp=distS[j]+distM[i][j];
                }
                dp[index][i]=tp;
            }
            //初始化从M到M经过O的最短距离
            for(int i=0;i<p;i++)
            {
                for(int j=0;j<p;j++)
                {
                    if(i==j){
                        distMM[i][j]=0;
                        continue;
                    }
                    for(int k=0;k<s;k++)
                    {
                        distMM[i][j]=min(distMM[i][j],distM[i][k]+distM[j][k]);
                    }
                }
            }
            /*for(int i=0;i<p;i++)
            {
                for(int j=0;j<p;j++)
                    cout<<distMM[i][j]<<" ";
                cout<<endl;
            }*/
            //状压dp,同旅行商问题
            for(int mask=0;mask<(1<<p);mask++)
            {
                for(int i=0;i<p;i++)
                {
                    if((1<<i)&mask) //如果i已经在mask状态中
                    {
                        for(int j=0;j<p;j++)
                        {
                            if(j!=i&&((1<<j)&mask))
                            {
                                dp[mask][i]=min(dp[mask][i],dp[mask-(1<<i)][j]+distMM[j][i]);
                            }
                        }
                    }
                }
            }
            int state=(1<<p)-1;
            int ans=INF;
            for(int i=0;i<p;i++)
                ans=min(ans,dp[state][i]+distT[i]);
            if(ans==INF)
                return -1;
            return ans;
        }
    
  • 相关阅读:
    python基础4
    python的基础数据类型和编码
    python的if语句和while循环
    java特殊运算符
    深入理解java集合
    python常用模块
    python函数的参数问题
    集合关系之间的运算
    集合
    可变类型与不可变类型
  • 原文地址:https://www.cnblogs.com/flightless/p/14095703.html
Copyright © 2020-2023  润新知