【动态规划刷题 6】 删除并获得点数&& 粉刷房子

740. 删除并获得点数

给你一个整数数组 nums ,你可以对它进行一些操作。
每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除 所有 等于 nums[i] - 1 和 nums[i] + 1 的元素。
开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。

链接: 740. 删除并获得点数
示例 1:
输入:nums = [3,4,2]
输出:6
解释:
删除 4 获得 4 个点数,因此 3 也被删除。
之后,删除 2 获得 2 个点数。总共获得 6 个点数。

示例 2:
输入:nums = [2,2,3,3,3,4]
输出:9
解释:
删除 3 获得 3 个点数,接着要删除两个 2 和 4 。
之后,再次删除 3 获得 3 个点数,再次删除 3 获得 3 个点数。
总共获得 9 个点数。

解法思路

从题目可以看出,本题和之前的 打家劫舍 系列题目有些类似,选取 i 后
i-1 和 i+1 都是不能选择的,但是该题我们无法直接进行动态规划,需要对数据进行预处理。

因此,我们可以创建⼀个⼤⼩为 10001 (根据题⽬的数据范围)的 arr 数组,将 nums 数组中每⼀个元素 x ,累加到 arr 数组下标为 x 的位置处,然后在 arr 数组上来⼀次「打家劫舍」即可。

代码:

   int deleteAndEarn(vector<int>& nums) {
    
    
        int N=10001;
        //预处理部分
        vector<int> arr(N);
        for(auto e:nums)
        {
    
    
            arr[e]+=e;
        }

        //动态规划解题部分
        vector<int> f(N),g(N);
        f[0]=arr[0];f[1]=arr[1];
        g[0]=0;g[1]=arr[0];

        for(int i=2;i<N;i++)
        {
    
    
            f[i]=g[i-1]+arr[i];
            g[i]=max(f[i-1],g[i-1]);
        }
        return max(f[N-1],g[N-1]);
    }

在这里插入图片描述

LCR 091. 粉刷房子

假如有一排房子,共 n 个,每个房子可以被粉刷成红色、蓝色或者绿色这三种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。

当然,因为市场上不同颜色油漆的价格不同,所以房子粉刷成不同颜色的花费成本也是不同的。每个房子粉刷成不同颜色的花费是以一个 n x 3 的正整数矩阵 costs 来表示的。

例如,costs[0][0] 表示第 0 号房子粉刷成红色的成本花费;costs[1][2] 表示第 1 号房子粉刷成绿色的花费,以此类推。

请计算出粉刷完所有房子最少的花费成本。

链接: LCR 091. 粉刷房子

示例 1:
输入: costs = [[17,2,17],[16,16,5],[14,3,19]]
输出: 10
解释: 将 0 号房子粉刷成蓝色,1 号房子粉刷成绿色,2 号房子粉刷成蓝色。
最少花费: 2 + 5 + 3 = 10。

示例 2:
输入: costs = [[7,6,2]]
输出: 2

1.状态表示

对于这种「路径类」的问题,我们的状态表⽰⼀般有两种形式:

  1. i. 从 [i, j] 位置出发,……;
  2. ii. 从起始位置出发,到达 [i, j] 位置,……;

这⾥我们选择⽐较常⽤的⽅式,以某个位置为结尾,结合题⽬要求,定义⼀个状态表⽰:
可以看出,以某个位置为结尾时,结尾处会有三种状态,分别对应着三种颜色,
所以我们定义一个二维数组:

  1. dp[i][0] 表⽰:粉刷到 i 位置的时候,最后⼀个位置粉刷上「红⾊」,此时的最⼩花费;
  2. dp[i][1] 表⽰:粉刷到 i 位置的时候,最后⼀个位置粉刷上「蓝⾊」,此时的最⼩花 费;
  3. ▪ dp[i][2] 表⽰:粉刷到 i 位置的时候,最后⼀个位置粉刷上「绿⾊」,此时的最⼩花 费。

2.状态转移方程

对于 dp[i][0] :

如果第i个位置粉刷上「红⾊」,那么 i-1 位置上可以是「蓝⾊」或者「绿⾊」。因此我们需要知道粉刷到i-1位置上的时候,粉刷上「蓝⾊」或者「绿⾊」的最⼩花费,然后加上i位置的花费即可。于是状态转移⽅程为:

dp[i][0] = min(dp[i - 1][1], dp[i- 1][2]) + costs[i - 1][0] ;

同理,可以推出

dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i - 1][1] ;
dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + costs[i - 1][2] 

3. 初始化

由状态转移方程可知,当 i 为0时,i-1不存在于数组下标中,所以需要对三个
位置进行初始化

		dp[0][0]=costs[0][0];
        dp[1][0]=costs[0][1];
        dp[2][0]=costs[0][2];

4. 填表顺序
根据「状态转移⽅程」得「从左往右,三个表⼀起填」。

5. 返回值
根据「状态表⽰」,应该返回最后⼀个位置粉刷上三种颜⾊情况下的最⼩值,因此需要返回:

min(dp[n--1][0], min(dp[n-1][1], dp[n-1][2])) 

代码:

 int minCost(vector<vector<int>>& costs) {
    
    
        int n=costs.size();
        vector<vector<int>> dp(3,vector<int>(n));

        dp[0][0]=costs[0][0];
        dp[1][0]=costs[0][1];
        dp[2][0]=costs[0][2];

        for(int i=1;i<n;i++)
        {
    
    
            dp[0][i]=min(dp[1][i-1],dp[2][i-1])+costs[i][0];
            dp[1][i]=min(dp[0][i-1],dp[2][i-1])+costs[i][1];
            dp[2][i]=min(dp[1][i-1],dp[0][i-1])+costs[i][2];
        }

        return min(dp[0][n-1],min(dp[1][n-1],dp[2][n-1]));

    }

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_64579278/article/details/132198011