• 刷题记录:牛客NC51170石子合并


    传送门:牛客

    题目描述:

    设有N堆沙子排成一排,其编号为1,2,3,\dots ,N1,2,3,…,N(N\leq 300)(N≤300)。每堆沙子
    有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆,每次只能合并相邻的两堆,合
    并的代价为这两堆沙子的数量之和,合并后与这两堆沙子相邻的沙子将和新堆相邻,合并时由于选择的顺序
    不同,合并的总代价也不相同,如有4堆沙子分别为 1 3 5 2 我们可以先合并1、2堆,代价为4,得到4 5 2 
    又合并 1,2堆,代价为9,得到9 2 ,再合并得到11,总代价为4+9+11=24,如果第二步是先合并2,3堆,
    则代价为7,得到4 7,最后一次合并代价为11,总代价为4+7+11=22;问题是:找出一种合理的方法,使总
    的代价最小。输出最小代价。
    输入:
    4
    1 3 5 2
    输出:
    22
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这道题的简化版,但是具体的dp想法是一样的,可以说是一道经典的区间dp

    主要思路:

    1. 对于这种区间dp题我们应该可以想到一个朴素的想法,就是使用一个 d p 数组 dp数组 dp数组来记录 区间 i 和区间 j 合并成一堆时需要的最小代价 区间i和区间j合并成一堆时需要的最小代价 区间i和区间j合并成一堆时需要的最小代价,并且对于这种线性合并的题目,我们还需要前缀和进行一个区间维护,为了能快速的得到区间和
    2. 那么对于我们的一个区间,假设我们在之前已经维护了这个区间内的一个个小区间(区间dp就是从小区间到大区间的,所以是可以维护的),那么我们显然的就可以使用小区间来递推到大区间,因为显然的一个大区间可以分成两个小区间(也就是意味着我们先合并两个小区间,最后再进行合并,这是可以操作的,因为每一个大区间最后一定是由两个小区间进行合并的),也就是说我们使用一个中间值作为我们的大区间的分割点的话,我们可以得到以下的转移方程

    d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i ] [ k ] + d p [ k + 1 ] [ j ] + s u m [ j ] − s u m [ i − 1 ] dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1] dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]sum[i1]

    注意我们的dp数组是需要初始化一下的,不然的话我们的dp数组就会一直会是0了

    下面是具体的代码部分:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    typedef long long ll;
    #define inf 0x3f3f3f3f
    #define root 1,n,1
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    inline ll read() {
    	ll x=0,w=1;char ch=getchar();
    	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    	return x*w;
    }
    #define maxn 1000000
    #define ll_maxn 0x3f3f3f3f3f3f3f3f
    const double eps=1e-8;
    int n;int dp[1000][1000];
    int a[1000];int sum[1000];
    int main() {
    	n=read();
    	for(int i=1;i<=n;i++) {
    		a[i]=read();sum[i]=sum[i-1]+a[i];
    	}
    	for(int len=2;len<=n;len++) {
    		for(int l=1;l<=n-len+1;l++) {
    			int r=l+len-1;
    			dp[l][r]=dp[l][l]+dp[l+1][r]+sum[r]-sum[l-1];
    			for(int k=l+1;k<=r-1;k++) {
    				dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+sum[r]-sum[l-1]);
    			}
    		}
    	}
    	cout<<dp[1][n]<<endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    怎样用python爬虫实现自动监测百度是否收录域名
    三、C语言常用运算符
    基于SSM SpringBoot vue家教交流平台
    Spring Boot 的启动原理、Spring Boot 自动配置原理
    java开发手册-06工程结构
    QT连接SQLITE 数据库
    系统架构设计师(第二版)学习笔记----计算机语言
    基于单片机的纸牌24点游戏模拟器设计
    Python函数式编程
    Git学习 —— 在IDEA中使用Git
  • 原文地址:https://blog.csdn.net/yingjiayu12/article/details/127682641