【DP】LeetCode - 120. Triangle、贝壳找房“采木头,锯子斧头”问题

锯子和斧头轮流砍树问题: 第一行输入树的个数 n, 接下来的 n 行,每行分别输入三个数 a、b、c,分别代表用锯子和斧头砍该棵树的时间,以及换工具砍树所需要的时间。现在手上是斧头,问看完这些树,最短需要多长时间。
输入:
3
20 40 20
10 4 25
90 100 5
输出:139

Explanation:第一棵树用斧头砍(40),第二颗树还用斧头(4),第三棵树,换成锯子(5 + 90)

  在牛客上看题,看到了一道用锯子斧头砍木头的问题,感觉应该很简单,但是同学说他提交只过了 9%,看了看代码感觉没有任何问题,最后再找到原因。首先这道题就是贪心,其实不是dp,叫dp也可以,就是

dp[0] = min(dp[0], dp[1] + b + c) + a;
dp[1] = min(dp[1], dp[0] + a + c) + b;

其中,dp[0] 是锯子,dp[1] 是斧头,a、b、c分别是当前次,锯子、斧头、切换工具的消耗。逻辑很简单,但是上边的代码有一个隐蔽的漏洞个,就是在算 dp[1] 的时候是用到 dp[0] 的值的,dp[0] 已经修改了,所以需要先存起来才行。代码如下:

#include 
#include 
using namespace std;
int main() {
     
	int n, a, b, c;
	cin >> n >> a >> b >> c;
	int dp[2] = {
      a + c, b };	// 0: 锯子, 1: 斧头
	for (int i = 1; i < n; ++i) {
     
		cin >> a >> b >> c;
		const int dp0 = dp[0];
		dp[0] = min(dp[0], dp[1] + c) + a;
		dp[1] = min(dp[1], dp0 + c) + b;
	}
	cout << min(dp[0], dp[1]) << endl;
}

  这就是为什么很多人只过了 9%。
  这道题和 120. Triangle 是一样的,都可以从上到下dp,也可以从下到上dp。

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
For example, given the following triangle
[
[2],
[3, 4],
[6, 5, 7],
[4, 1, 8, 3] ]
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

Note:

Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.

  题目里也写了用 O(N) 的空间,也就是和上边的思路意义一样,其实每一层只需要上一层的(从上到下),或者只需要下一层的(从下到上),只有一个一维数组就行,不需要全存起来。代码如下:

// top-down 
int minimumTotal1(vector<vector<int>>& triangle) {
     
    vector<int> res(triangle.size(), triangle[0][0]);
    for (unsigned int i = 1; i < triangle.size(); i++) 
        for (int j = i; j >= 0; j--) {
     
            if (j == 0)
                res[0] += triangle[i][0];
            else if (j == i)
                res[j] = triangle[i][j] + res[j - 1];
            else 
                res[j] = triangle[i][j] + min(res[j - 1], res[j]);
        }
    return *min_element(res.begin(), res.end());
}

// bottom-up
int minimumTotal(vector<vector<int>>& triangle) {
     
    vector<int> res = triangle.back();
    for (int i = triangle.size() - 2; i >= 0; i--) 
        for (unsigned int j = 0; j <= i; j++) 
            res[j] = triangle[i][j] + min(res[j], res[j + 1]);
    return res[0];
}

你可能感兴趣的:(LeetCode,Algorithm,#,编程题,LeetCode,dp)