leetcode-1547

题目:切棍子的最小成本。
题目链接:https://leetcode.cn/problems/minimum-cost-to-cut-a-stick/description/

今天继续讲解一个关于区间dp的题目,还是以dfs-dp的流程来解决这道题

题目描述:有一根长度为 n 个单位的木棍,棍上从 0 到 n 标记了若干位置,给你一个整数数组 cuts ,其中 cuts[i] 表示你需要将棍子切开的位置。你可以按顺序完成切割,也可以根据需要更改切割的顺序。每次切割的成本都是当前要切割的棍子的长度,切棍子的总成本是历次切割成本的总和。对棍子进行切割将会把一根木棍分成两根较小的木棍(这两根木棍的长度和就是切割前木棍的长度)。请参阅第一个示例以获得更直观的解释。返回切棍子的 最小总成本 。

经过分析,对于这道题我们可以用数组ans[i][j]来表示一组cuts数组中第i位置到第j位置上的节点还未进行分割。那么对于cuts数组来说,cuts数组的顺序对答案没有影响,所以我们可以将cuts数组进行排序(优点会在设计状态转移方程时进行解释)

设计dfs:
我们用两个参数【left,right】来表示在【left,right】范围内的节点未分割。
我们可以在这个范围内找到一个节点k(left<=k<=right)来作为一个分割点,代价是分割【left,k-1】的最小代价+分割【k+1,right】的最小代价+本次分割的代价。
如何求得本次分割的代价?

现在利用题目的样例来进行解释
输入n = 9, cuts = [5,6,1,4,2]
进行排序后的cuts数组

0 1 2 3 4 5 6
0 1 2 4 5 6 9

如果现在【2,5】位置上还没有进行分割,分割的代价=cuts[5+1]-cuts[2-1]。

点击查看代码
int dfs(int left, int right)
{
    if (left > right)
        return 0;
    if (left == right)
    {
        return ans[left][right] = cuts[left + 1] - cuts[left - 1];
    }
    int minn = 0x3f3f3f3f;
    for (int i = left; i <= right; i++)
    {
        minn = min(minn, dfs(left, i - 1) + dfs(i + 1, right) + cuts[right + 1] - cuts[left - 1]);
    }
    return minn;
}

区间dp方法
ans数组和dfs中ans数组功能相同,通过分析dfs的递归操作我们能够发现我们如果要求解某一区间【left,right】的最小分割代价时需要知道分割节点k和【left,k-1】,【k+1,right】的最小分割代价。映射到数组空间我们会发现需要依赖左边位置的数组和下面位置上的数组,所以我们还是从下往上进行dp

点击查看代码
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;
#define int long long

void solve()
{
	int n, m;
	cin >> n >> m;
	vector<int> arr(m + 5);
	for (int i = 1; i <= m; i++)
	{
		cin >> arr[i];
	}
	sort(arr.begin() + 1, arr.begin() + 1 + m);
	arr[m + 1] = n;
	vector<vector<int>> ans(m + 5, vector<int>(m + 5));
	for (int i = 1; i <= m; i++)
	{
		ans[i][i] = arr[i + 1] - arr[i - 1];
	}
	for (int i = m; i >= 1; i--)
	{
		for (int j = i + 1; j <= m; j++)
		{
			for (int k = i; k <= j; k++)
			{
				if (!ans[i][j])
					ans[i][j] = ans[i][k - 1] + ans[k + 1][j] + arr[j + 1] - arr[i - 1];
				else
					ans[i][j] = min(ans[i][j], ans[i][k - 1] + ans[k + 1][j] + arr[j + 1] - arr[i - 1]);
			}
		}
	}
	cout << ans[1][m] << endl;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	// cin >> t;
	while (t--)
	{
		solve();
	}
}

根据dfs设计动态规划的方法之前已经讲过不做过多解释,有疑问可以去看 https://www.cnblogs.com/zznu/p/19029100

posted @ 2025-09-07 17:03  zznu_ybk  阅读(36)  评论(0)    收藏  举报