当前位置: 首页 > news >正文

数据结构与算法:二维动态规划

前言

当递归函数有两个可变参数时,改成的动态规划就是二维的。

一、从递归到二维动态规划

1.最小路径和

class Solution {
public:

    vector<int>move={0,1,0};

    static bool cmp(vector<int>&a,vector<int>&b)
    {
        return a[2]>b[2];
    }

    int minPathSum(vector<vector<int>>& grid) {
        int n=grid.size();
        int m=grid[0].size();
        //return dijkstra(n,m,grid);
        //return recursion(0,0,n,m,grid);
        //vector<vector<int>>dp(n,vector<int>(m,-1));
        //return memorized_search(0,0,n,m,grid,dp);
        //return dynamic_programming(n,m,grid);
        return optimized_dp(n,m,grid);
    }

    int dijkstra(int n,int m,vector<vector<int>>&grid)
    {
        vector<vector<int>>distance(n,vector<int>(m,INT_MAX));
        distance[0][0]=grid[0][0];
        vector<vector<bool>>visited(n,vector<bool>(m,false));
        priority_queue<vector<int>,vector<vector<int>>,decltype(&cmp)>heap(cmp);
        heap.push({0,0,grid[0][0]});

        while(!heap.empty())
        {
            int x=heap.top()[0];
            int y=heap.top()[1];
            heap.pop();

            if(!visited[x][y])
            {
                if(x==n-1&&y==m-1)
                {
                    return distance[x][y];
                }

                visited[x][y]=true;

                for(int i=0;i<2;i++)
                {
                    int nx=x+move[i];
                    int ny=y+move[i+1];
                    
                    if(nx>=0&&nx<n&&ny>=0&&ny<m&&!visited[nx][ny])
                    {
                        if(grid[nx][ny]+distance[x][y]<distance[nx][ny])
                        {
                            distance[nx][ny]=grid[nx][ny]+distance[x][y];
                            heap.push({nx,ny,distance[nx][ny]});
                        }
                    }
                }
            }
        }

        return -1;
    }

    //递归 -> 超时
    int recursion(int x,int y,int n,int m,vector<vector<int>>&grid)
    {
        if(x==n-1&&y==m-1)
        {
            return grid[x][y];
        }
        if(x<0||x>n-1||y<0||y>m-1)
        {
            return INT_MAX;
        }

        int ans=grid[x][y]+min(recursion(x,y+1,n,m,grid),recursion(x+1,y,n,m,grid));

        return ans;
    }

    //记忆化搜索 -> 超时
    int memorized_search(int x,int y,int n,int m,vector<vector<int>>&grid,vector<vector<int>>&dp)
    {
        if(x==n-1&&y==m-1)
        {
            return grid[x][y];
        }
        if(x<0||x>n-1||y<0||y>m-1)
        {
            return INT_MAX;
        }

        if(dp[x][y]!=-1)
        {
            return dp[x][y];
        }

        int ans=grid[x][y]+min(recursion(x,y+1,n,m,grid),recursion(x+1,y,n,m,grid));
        dp[x][y]=ans;
        return ans;
    }

    //动态规划
    int dynamic_programming(int n,int m,vector<vector<int>>&grid)
    {
        vector<vector<int>>dp(n,vector<int>(m));
        dp[n-1][m-1]=grid[n-1][m-1];

        for(int i=n-1;i>=0;i--)
        {
            for(int j=m-1;j>=0;j--)
            {
                if(i==n-1&&j==m-1)
                {
                    continue;
                }
                dp[i][j]=grid[i][j]+min(i+1<=n-1?dp[i+1][j]:INT_MAX,j+1<=m-1?dp[i][j+1]:INT_MAX);
            }
        }

        return dp[0][0];
    }

    //空间压缩
    int optimized_dp(int n,int m,vector<vector<int>>&grid)
    {
        vector<int>dp(m);
        //初始化
        dp[m-1]=grid[n-1][m-1];
        for(int j=m-2;j>=0;j--)
        {
            dp[j]=dp[j+1]+grid[n-1][j];
        }

        for(int i=n-2;i>=0;i--)
        {
            dp[m-1]=grid[i][m-1]+dp[m-1];
            for(int j=m-2;j>=0;j--)
            {
                dp[j]=grid[i][j]+min(dp[j],dp[j+1]);
            }
        }

        return dp[0];
    }
};

其实这个题用dijkstra也能做。()

观察可知,递归函数肯定有两个可变参数,一个是x坐标一个是y坐标。那么之后就是到了终点就返回终点格子的大小,否则就是当前格子的大小加上下边和右边的最小值。又因为要比较最小值,所以当越界的时候要返回无穷大。

之后记忆化搜索就是挂个dp表即可。

再就是改动态规划,在二维动态规划中,由于有两个可变参数,所以dp表呈现的形式是一个二维网格。之后分析严格位置依赖可知,每个格子依赖自己右方和下方的格子,那么在填格子的时候就从下往上,从右往左填。

然后因为只依赖自己下方和右方的格子,那么就可以只用一个一维数组,只表示当前一行。之后从下往上滚动更新即可。

2.单词搜索

这个题想说明的就是带路径的递归不适合改动态规划。

class Solution {
public:

    vector<int>move={-1,0,1,0,-1};

    bool exist(vector<vector<char>>& board, string word) {
        for(int i=0;i<board.size();i++)
        {
            for(int j=0;j<board[0].size();j++)
            {
                if(recursion(i,j,0,word,board))
                {
                    return true;
                }
            }
        }
        return false;
    }

    bool recursion(int x,int y,int i,string &word,vector<vector<char>>&board)
    {
        if(i==word.length())
        {
            return true;
        }
        if(x<0||x>=board.size()||y<0||y>=board[0].size()||board[x][y]!=word[i])
        {
            return false;
        }

        char tmp=board[x][y];//带路径!!!
        board[x][y]=0;
        bool ans=false;
        for(int j=0;j<4;j++)
        {
            ans|=recursion(x+move[j],y+move[j+1],i+1,word,board);
        }
        board[x][y]=tmp;//还原现场
        return ans;
    }
};

因为要求不能走回头路,那么每来到一个格子,都要先把当前格子改成0,之后在回来的时候再还原。那么由此可知,每次递归的时候,可变参数不只两个坐标,还有整个棋盘格,所以没法改成动态规划。

那么整体思路就是遍历棋盘格,即讨论以每个点开头的情况,

相关文章:

  • 图解AUTOSAR_SWS_CANDriver
  • 【区块链安全 | 第二十四篇】单位和全局可用变量(二)
  • 翻译: 人工智能如何让世界变得更美好四
  • BERT与Transformer到底选哪个-下部
  • css_z-index属性
  • C++STL---<functional>
  • 如何使用fiddler抓取手机APP的包,进行前后端bug定位
  • pyproj 库中Geod类—geod.npts()方法讲解
  • 智能制造:MES系统架构设计
  • github合并多个commit message以及rebase解决文件冲突
  • cisco简单DHCP配置
  • 第三章:ROS基础_《ROS机器人开发实践》_notes
  • 【全队项目】智能学术海报生成系统PosterGenius--风格个性化调整
  • vulnhub-serile靶机通关攻略
  • 在PyCharm 中免费集成Amazon CodeWhisperer
  • 【CSS3】04-标准流 + 浮动 + flex布局
  • 【大模型基础_毛玉仁】5.4 定位编辑法:ROME
  • 嵌入式图像采集与显示系统实战详解:基于V4L2与Framebuffer的实现
  • 单元测试中的测试替身(基于Java的示例)
  • 21 模板方法(Template Method)模式
  • 10个网站做站群/软文自助发稿平台
  • 做网站最大的公司/谷歌代理
  • 免费微信小程序开店/河北网站seo地址
  • 三丰云做游戏网站/优秀软文营销案例
  • 建设机械员证书查询网站/2022年最新热点素材
  • 中国可信网站查询/成都高薪seo