动态规划 2019.10

动态规划

记忆化搜索


1.记忆化搜索必须满足动态规划从初始状态到最终状态
2.记忆化搜索中,搜索相当于“标记访问”
leetcode 329 矩阵中的最长递增路径和:
      1.每个点从大往小搜
      2.每个点从小往大搜
      3.上述都可以
leetcode 354 俄罗斯套娃问题:
      1.二维判断
方法1:记忆化搜索

int medfs(int index, vector<vector<int>> &nums)
    {
        // cout<<"i: "<<index<<endl;
        
        if (dp[index]!=0)
            return dp[index];
        
        int curmax=0;
        for (int i=0; i<nums.size(); i++)
        {
            if (nums[i][0]<nums[index][0] && nums[i][1]<nums[index][1])
            {
                curmax=max(curmax, medfs(i, nums));
            }
        }
        
        // cout<<"dp: "<<dp[index]+1<<endl;
        
        return dp[index]=curmax+1;//注意赋值
    }
    
    int maxEnvelopes(vector<vector<int>>& nums) 
    {
        if (nums.size()==0)
            return 0;
        
        memset(dp, 0, sizeof(dp));
        int MAX=-INF;
        for (int i=0; i<nums.size(); i++)
        {
            if (!dp[i])
            {
                MAX = max(MAX, medfs(i, nums));
                // cout<<"zong i "<<i<<"  "<<dp[i]<<"***********************"<<endl;
            }
        }
        
        // cout<<"dp3"<<dp[3]<<endl;
        
        return MAX;
    }

方法2:自底向上

static bool cmp(vector<int> &a, vector<int> &b)
    {
        if (a[0]!=b[0])
            return a[0]<b[0];
        else
            return a[1]<b[1];
    }
    
    int maxEnvelopes(vector<vector<int>>& nums) 
    {
        if (nums.size()==0)
            return 0;
        
        fill(dp, dp+nums.size(), 1);
        int MAX=-INF;

        sort(nums.begin(), nums.end(), cmp);
        
        for (int i=0; i<nums.size(); i++)
        {
            for (int j=0; j<nums.size(); j++)
            {
                if (j != i && nums[j][0]>nums[i][0] && nums[j][1]>nums[i][1])
                {
                    dp[j] = max(dp[j], dp[i]+1);
                }
            }
            
            if (dp[i] > MAX)
            {
                MAX=dp[i];
            }
            
            
        }
        
        
        return MAX;
    }

leetcode 174 地下城问题:
      1.在记忆化搜索的过程中,需要状态不只依赖后续前状态,还需对状态判断,做手动处理

int medfs(int i, int j, int m, int n, vector<vector<int>> &dungeon, int dp[maxn][maxn]) //记忆化搜索
    {
        if (i==m-1 && j==n-1)//目标点
            return dungeon[i][j];
        
        if (dp[i][j]!=0)//0不能单纯的做标记(图中存在0结点)
            return dp[i][j];
        
        
        int curmax=-INF;//最大负数
        
        for (int k=0; k<2; k++)
        {
            int newi=i+dir[k][0];
            int newj=j+dir[k][1];
            if (0<=newi && newi<m && 0<=newj && newj<n)
            {
                curmax = max(curmax, medfs(newi, newj, m, n, dungeon, dp));
            }
        }
        
        
        // cout<<i<<" "<<j<<": "<<curmax<<endl;
        curmax = curmax>0 ? 0:curmax;
        return dp[i][j] = dungeon[i][j] + curmax;
    }

//主函数中返回的额外判断
if (dp[0][0]<0)
	return abs(dp[0][0])+1;
else
	return 1;

leetcode 377 组合总和4:
     1.使用记忆化搜索(复杂错误思想->正确思想)
错误思想:

//错误: 简单问题复杂化
//记忆化搜索
//dp是bool变量
const int maxn=10005;
int dp[maxn];
int visited[maxn];//增加标记访问

class Solution {
public:
    int dfs(vector<int>& nums, int target)
    {
        
        if (target==0)//边界
            return 0;
        
        //记忆化
        if (dp[target]==0 && visited[target])
            return 0;
        if (dp[target]!=0 && dp[target]!=1)
            return dp[target];
        
        for (int i=0; i<nums.size(); i++)
        {
            if (target>=nums[i])
            {
                dp[target]+=dfs(nums, target-nums[i]);
            }
                
        }
        
        visited[target]=1;
        
        return dp[target];
    }
    
    int combinationSum4(vector<int>& nums, int target) 
    {
        // 0%1 == 0;
        if (nums.size()==0)
            return 0;
        
        
        //init
        memset(dp, 0, sizeof(dp));
        memset(visited, 0, sizeof(visited));

        for (int i=0; i<nums.size(); i++)
        {
            dp[nums[i]]=1;
        }
        
        int ans = dfs(nums, target);
        
        return ans;
    }
};

正确思想:

//记忆化搜索
//dp是bool变量
const int maxn=10005;
int dp[maxn];
int visited[maxn];//增加标记访问

class Solution {
public:
    int dfs(vector<int>& nums, int target)
    {        
        if (target==0)//边界//能达到边界就是一个结果
            return 1;
        
        //记忆化
        if (visited[target])
            return dp[target];
        
        for (int i=0; i<nums.size(); i++)
        {
            if (nums[i]<=target)
            {
                dp[target]+=dfs(nums, target-nums[i]);
            }
                
        }
        
        visited[target]=1;
        
        return dp[target];//如果都填不上会返回0
    }
    
    int combinationSum4(vector<int>& nums, int target) 
    {
        if (nums.size()==0)
            return 0;
        
        //init
        memset(dp, 0, sizeof(dp));
        memset(visited, 0, sizeof(visited));
        
        int ans = dfs(nums, target);
        
        return ans;
    }
};

2019.10


leetcode 279 完全平方数:
1.如何从暴力搜索(重叠子问题)->记忆化->自底向上动态规划
2.每个状态使用可能使用序列之前数字的状态->二重循环
3.初,使用了完全背包,有很大的冗余(但是本题类似于完全背包)

int numSquares(int n) 
    {
        int dp[maxn];
        
        dp[0]=0;
        for (int i=1; i<=n; i++)
        {
            dp[i]=i;//初始化(1也是完全平方数)
            for (int j=1; i-j*j>=0; j++)
            {
                dp[i]=min(dp[i], dp[i-j*j]+1);//+1体现了动态规划自底向上
            }
            
        }
        
        return dp[n];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值