【六月集训】day28 动态规划

2310. 个位数字为 K 的整数之和

题目描述:

给你两个整数 num 和 k ,考虑具有以下属性的正整数多重集:

每个整数个位数字都是 k 。
所有整数之和是 num 。
返回该多重集的最小大小,如果不存在这样的多重集,返回 -1 。

注意:

多重集与集合类似,但多重集可以包含多个同一整数,空多重集的和为 0 。
个位数字 是数字最右边的数位。

思路:

1、将所有个位数字为k的数初始化出来,总共300个,(num最大3000)
2、然后每个数字是一个物品的容量,物品的消耗为1
3、背包的总容量为num,于是就转变为一个 完全背包 问题,求完全背包的容量为num的最小消耗

class Solution {
    int pack[310],packsize;
public:
    int minimumNumbers(int num, int k) {
        packsize = 0;
        int dp[3010];
        //将所有个位数字为k的数初始化出来,总共300个
        for (int i = 0; i <= num; ++i) {
            if (i % 10 == k) {
                pack[++packsize] = i; 
            }
        }

        for (int j = 0; j <= num; ++j) {
            dp[j] = 100000000;
        }
        dp[0] = 0;
        for (int i = 1; i <= packsize; ++i) {
            for (int j = pack[i]; j <= num; ++j) {
                //dp[j - pack[i]] + 1 表示前i个数组合出j,所需要的数字的最小个数
                if (dp[j - pack[i]] + 1 < dp[j]) {
                    dp[j] = dp[j - pack[i]] + 1;
                }
            }
        }
        return dp[num] >= 100000000 ? -1:dp[num];

        
    }
};

1594. 矩阵的最大非负积

题目描述:

给你一个大小为 rows x cols 的矩阵 grid 。最初,你位于左上角 (0, 0) ,每一步,你可以在矩阵中 向右 或 向下 移动。

在从左上角 (0, 0) 开始到右下角 (rows - 1, cols - 1) 结束的所有路径中,找出具有 最大非负积 的路径。路径的积是沿路径访问的单元格中所有整数的乘积。

返回 最大非负积 对 109 + 7 取余 的结果。如果最大积为负数,则返回 -1 。

注意,取余是在得到最大积之后执行的

思路:

1、用户dpmin[i][j]记录从(0,0)点到(i,j)点的最小乘积,用dpmax[i][j]记录从(0,0)点到(i,j)点的最大乘积,每次都需要求最大值和最小值,因为可能是负数,最后取最大值即可。
2、每次状态转移可以从左边来,或者从上边来,于是进行m*n的状态转移以后,得到dpmax[m-1][n-1]的值就是最后的答案了,如果它小于0,则输出-1,别忘了取模

class Solution {
    #define ll long long
    ll dpmin[16][16], dpmax[16][16];
    ll getmin(int now, int i, int j) {
        return min(dpmin[i][j]*now, dpmax[i][j]*now);
    }
    ll getmax(int now, int i, int j) {
        return max(dpmin[i][j]*now, dpmax[i][j]*now);
    }
public:
    int maxProductPath(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();

        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (!i & !j) { //i=j=0,初始化dpmax和dpmin
                    dpmax[i][j] = dpmin[i][j] = grid[i][j];
                } else if(!i) { //i=0时只能从上面下来
                    dpmax[i][j] = getmax(grid[i][j], i, j-1);
                    dpmin[i][j] = getmin(grid[i][j], i, j-1);
                } else if(!j) {//j=0时只能从左边下来
                    dpmax[i][j] = getmax(grid[i][j], i-1, j);
                    dpmin[i][j] = getmin(grid[i][j], i-1, j);
                } else  {
                    dpmax[i][j] = getmax(grid[i][j], i, j-1);
                    dpmax[i][j] = max(dpmax[i][j], getmax(grid[i][j], i-1, j));
                    dpmin[i][j] = getmin(grid[i][j], i, j-1);
                    dpmin[i][j] = min(dpmin[i][j], getmin(grid[i][j], i-1, j));
                }
            }
        }

        if (dpmax[m-1][n-1] < 0) return -1;
        else return dpmax[m-1][n-1]%1000000007;
    }
    
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值