首页 > 其他分享 >leetcode1000. 合并石头的最低成本

leetcode1000. 合并石头的最低成本

时间:2023-04-06 17:45:30浏览次数:61  
标签:stones leetcode1000 int make 合并 石头 ++ dp

有 N 堆石头排成一排,第 i 堆中有 stones[i] 块石头。

每次移动(move)需要将连续的 K 堆石头合并为一堆,而这个移动的成本为这 K 堆石头的总数。

找出把所有石头合并成一堆的最低成本。如果不可能,返回 -1

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/minimum-cost-to-merge-stones

解决

经典的石子归并的题目,不过是三维的dp,想清楚是比较复杂的。记录一下。
dp状态和递推方程不难想到,但是怎么遍历想了很久,毕竟3维。子问题是解决小区间的合并,再大区间。


const INF = 1e8 + 7

var n int
var dp [][][]int

func Init(k int) {
	dp = make([][][]int, n)
	for i := 0; i < n; i++ {
		dp[i] = make([][]int, n)
		for j := 0; j < n; j++ {
			dp[i][j] = make([]int, k+1)
			for p := 0; p < k+1; p++ {
				dp[i][j][p] = INF
			}
		}
	}
}

func mergeStones(stones []int, k int) int {
	n = len(stones)
	Init(k)

	pre := make([]int, n+1)
	for i := 0; i < n; i++ {
		pre[i+1] = pre[i] + stones[i]
		dp[i][i][1] = 0
	}

	for ll := 1; ll <= n; ll++ { // 确定该轮遍历的区间长度
		for l := 0; l < n && l+ll < n; l++ { // 确定左,右边界
			r := l + ll
			for p := 2; p <= k; p++ { // 区间分p堆
				for s := l; s < r; s++ {
					dp[l][r][p] = min(dp[l][r][p], dp[l][s][1]+dp[s+1][r][p-1]) // dp[l][r][p] = min{ dp[l][s][1] + dp[s+1][r][p-1] }
					// fmt.Println("cp2", l, r, s, p, dp[l][r][p])
				}
			}
			dp[l][r][1] = min(dp[l][r][1], dp[l][r][k]+pre[r+1]-pre[l]) // dp[l][r][1] = dp[l][r][k] + sum[l,r]
		}
	}

	if dp[0][n-1][1] == INF {
		return -1
	}
	return dp[0][n-1][1]
}

func min(j, k int) int {
	if j < k {
		return j
	}
	return k
}

func main() {
	//stones := []int{1, 2, 3}
	//K := 2
	//fmt.Println(mergeStones(stones, K))

	stones := []int{3, 5, 1, 2, 6}
	K := 3
	fmt.Println(mergeStones(stones, K))

	stones = []int{1}
	K = 2
	fmt.Println(mergeStones(stones, K))

	stones = []int{5, 4}
	K = 3
	fmt.Println(mergeStones(stones, K))
}

标签:stones,leetcode1000,int,make,合并,石头,++,dp
From: https://www.cnblogs.com/haoabcd2010/p/17293570.html

相关文章

  • 动态开点线段树&线段树合并学习笔记
    动态开点线段树使用场景\(4\timesn\)开不下。值域需要平移(有负数)。什么时候开点显然,访问的节点不存在时(只会在修改递归时开点)。trick区间里面有负数时,\(mid=(l+R-1)/2\)。防止越界。例如区间\([-1,0]\)。开点上限考虑到update一次最多开\(\logV\)个......
  • python 合并多个PPT
    #encoding=utf8#-*-coding:utf-8-*-#pipinstallaspose.slides-ihttps://pypi.tuna.tsinghua.edu.cn/simpleimportaspose.slidesasslidesfrompptximportPresentation#导入PPT库importwin32com.client,sysfromglobimportglob#打開第一張PPTwith......
  • python用于新建空文件夹/文件&以时间命名的文件&文件夹内的文件合并
    '''用于新建空文件夹'''path="/root/temp/"defmake_Empty_Dir(path):'''如果path这个路径下存在文件夹,就先删除它,再新建它,如果不存在,就新建它,目的是为了temp为新的空文件夹'''importosimportshutilifos.path.isdir(path......
  • 合并两个有序链表
    将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。示例1:输入:l1=[1,2,4],l2=[1,3,4]输出:[1,1,2,3,4,4]示例2:输入:l1=[],l2=[]输出:[]示例3:输入:l1=[],l2=[0]输出:[0]提示:两个链表的节点数目范围是[0,50......
  • 代码随想录Day20-Leetcode654.最大二叉树,617.合并二叉树,700.二叉搜索树中的搜索,98.验
    654.最大二叉树题目链接:https://leetcode.cn/problems/maximum-binary-tree/基本的模拟思路很快/***Definitionforabinarytreenode.*functionTreeNode(val,left,right){*this.val=(val===undefined?0:val)*this.left=(left===undefined......
  • 启发式合并(树上)
    一般用于:查询每一个子树的相关所有信息, 内容:dfs,后,合并儿子的时候,继承一个重儿子,然后把其他儿子暴力合进去就行了,最坏的时间复杂度:NlongN 如何继承的时候不是暴力捏?给每一个点赋值一个新的ID,就行了. 重点是在结构体tr[]节点里面的各种定义的东西, ......
  • 23. 合并 K 个升序链表
    题目描述给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。解题1/**2*Definitionforsingly-linkedlist.3*publicclassListNode{4*intval;5*ListNodenext;6*ListNo......
  • git 选择合并
    需求:有两个分支,develop,master,需要把develop的提交记录,选择性合并到master1. 将ideal 切换到master分支,checkout 2.   3.根据提交记录,右键cherrypick   4.再执行push操作。合并完成......
  • 将List集合中相同属性的对象合并
    List<User>userList=newArrayList<>();List<User>userMergeList=newArrayList<>();userList.parallelStream().collect(Collectors.groupingBy(o->(o.getUserId()+o.getUserName()),Collectors.toList())).forEach((id,transfer)-&......
  • 石子合并问题
    相邻石子合并问题代码#include<bits/stdc++.h>usingnamespacestd;#definerep(i,a,n)for(inti=a;i<=n;i++)constintN=330;intsum[N];inta[N];intf[N][N];//从i到j合并石子所付出的最小代价intmain(){intn;cin>>n;rep(i,1,n){cin......