leetcode春季赛 LCP 31. 变换的迷宫 (动态规划)

题目链接

解题思路
首先我们容易想到一个简单的动态规划方法:
用dp[t][x][y][s][fx][fy]表示在时间t时,s(0或1)表示临时消除法是否使用,以及永久消除法已经用在点(fx,fy),点(x,y)能否到达。用递推来计算出所有dp状态的结果。
但是,这个方法的时间复杂度位O(Tnm2nm5),其中5为转移复杂度,最坏情况下约为10^9,复杂度太高。
我们来考虑如何优化这个dp表达式,显然时间t,坐标(x,y),状态s都无法优化。我们把优化重点放到永久消除卡上。
分类讨论:
1,如果我们使用永久消除卡后,不再回到永久消除卡使用的点,那么永久消除卡就相当于一个临时消除卡。
2,如果我们使用永久消除卡后,再回到永久消除卡使用的点,那么相当于我一直呆在这个点没有移动。我们可以用一直呆在这个点,等价替换离开这个点再回到这个点的情况。
因此我们就不用再开两维来记录永久消除卡使用在哪里,我们只需要记录永久消除卡是否使用。在状态转移的时候,若本次使用了永久消除卡,则更新一直待在这个点的其余状态。
具体来说,我们用dp[t][x][y][s],表示在时间t,s为状态消除卡使用状态(二进制最低位表示临时消除卡是否使用,二进制次低位表示永久消除卡是否使用),点(x,y)能否到达。用我们上述方法进行转移即可。转移细节见代码。

代码

class Solution {
public:
    bool escapeMaze(vector<vector<string>>& maze) {
        int T=maze.size();
        int dir[5][2]={1,0,-1,0,0,1,0,-1,0,0};
        int n=maze[0].size();
        int m=maze[0][0].size();
        bool dp[110][55][55][5];
        memset(dp,false,sizeof(dp));
        dp[0][0][0][0]=true;
        for(int t=0;t<T-1;t++)
        {
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<m;j++)
                {
                    for(int s=0;s<=3;s++)
                    {
                        if(!dp[t][i][j][s])
                            continue;
                        for(int k=0;k<5;k++)
                        {
                            int x=i+dir[k][0];
                            int y=j+dir[k][1];
                            if(x<0||x>=n||y<0||y>=m)
                                continue;
                            if(maze[t+1][x][y]=='.')
                            {
                                dp[t+1][x][y][s]=true;
                                if(x==n-1&&y==m-1)
                                    return true;
                            } else {
                                if((s&1)==0)
                                {
                                    dp[t+1][x][y][s|1]=true;
                                    if(x==n-1&&y==m-1)
                                        return true;
                                }
                                if((s&2)==0)
                                {
                                    if(x==n-1&&y==m-1)
                                        return true;
                                    for(int z=t+1;z<T;z++)
                                    {
                                        dp[z][x][y][s|2]=true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return false;
    }
};

作者:ma-lie
链接:https://leetcode-cn.com/problems/Db3wC1/solution/dong-tai-gui-hua-by-ma-lie-u5gc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

作者:ma-lie
链接:https://leetcode-cn.com/problems/Db3wC1/solution/dong-tai-gui-hua-by-ma-lie-u5gc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值