51Nod - 1021 石子归并

51Nod -  1021 石子归并

N堆石子摆成一条线。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。

例如: 1 2 3 4,有不少合并方法

1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)

1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)

1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)

括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。

Input

第1行:N(2 <= N <= 100)
第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)

Output

输出最小合并代价

Input示例

4
1
2
3
4

Output示例

19

题解:

  使用dp动态规划, dp[i][j] 表示的是从 第 i 到 第j个元素的合并最小和。 sum[i][j] 是第i到第j的累积和。 (包含第 i, j两个断点)

  有公式 dp[i][j] = min( dp[i][j],  dp[i][k] + dp[k+1][j] + sum[i][j] );

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 102; 

int n, num[MAXN], dp[MAXN][MAXN], sum[MAXN][MAXN]; 

int main(){

	while(scanf("%d", &n) != EOF){
		for(int i=1; i<=n; ++i){
			scanf("%d", &num[i]);
		}

		memset(sum, 0, sizeof(sum));
		for(int i=1; i<=n; ++i){
			for(int j=i; j<=n; ++j){
				sum[i][j] = sum[i][j-1] + num[j];
			}
		} 

		memset(dp, 0x3f3f3f3f, sizeof(dp));
		for(int i=0; i<=n; ++i){
			for(int j=0; j<=n; ++j){
				if(i >= j){
					dp[i][j] = 0;
				}
			}
		}
		for(int i=1; i<=n; ++i){
			for(int j=i-1; j>=1; --j){
				for(int k=j; k<i; ++k){
					dp[j][i] = min(dp[j][i], dp[j][k] + dp[k+1][i] + sum[j][i] );
				}
			}
		}
		printf("%d\n",  dp[1][n] );
	}
	return 0;
}

  

时间: 2024-10-13 10:47:00

51Nod - 1021 石子归并的相关文章

51nod 1021 石子归并(dp)

51nod 1021 石子归并 题解:从i到j合并的最小值:dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]); 最后dp[1][n]即为所求结果. 1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define CLR(a,b) memset((a),(b),sizeof((a))) 5 using name

51nod 1021 石子归并 (动态规划 简单代码)

题目: 思路:动态规划,递推式子 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);     dp[i][j]表示合并第i到第j个石子需要的最少代价.sum[i]表示前i个石子的价值,sum[j] - sum[i-1]即合成两堆石子((第i到第k合并出的石子),(第k+1到第j合并出的石子)). 但是考虑要求1-4, 需要先求出(1-1,2-4),(1-2,3-4),(1-3,4-4). 所以我们不能直接按横纵

51Nod - 1021 石子归并(区间DP)

[题目描述] N堆石子摆成一条线.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价.计算将N堆石子合并成一堆的最小代价. 例如: 1 2 3 4,有不少合并方法 1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19) 1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24) 1 2 3 4 => 1 2 7(7) => 3 7(10) => 1

51nod 1021 石头归并

1021 石子归并 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题  收藏  关注 N堆石子摆成一条线.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价.计算将N堆石子合并成一堆的最小代价. 例如: 1 2 3 4,有不少合并方法 1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19) 1 2 3 4 => 1 5 4(5) => 1 9(14) =>

[51nod 1022] 石子归并v2 [dp+四边形不等式优化]

题面: 传送门 思路: 加强版的石子归并,现在朴素的区间dp无法解决问题了 首先我们破环成链,复制一条一样的链并粘贴到原来的链后面,变成一个2n长度的序列,在它上面dp,效率O(8n^3) 显然是过不了的,需要优化 注意:dp的转移如下:dp[i][j]=min(dp[i][k]+dp[k+1][j]+sum(i,j)),其中sum(i,j)表示i到j的价值和,满足区间单调性 因此dp[i][j]也满足区间单调性,可以用四边形不等式优化 我们令s[i][j]等于让dp[i][j]取最小值的那个K

51Nod 1022 石子归并 V2(区间DP+四边形优化)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1022 题目大意: N堆石子摆成一个环.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价.计算将N堆石子合并成一堆的最小代价. 例如: 1 2 3 4,有不少合并方法 1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19) 1 2 3 4 => 1 5 4(5)

51nod 1022 石子归并 V2(四边形不等式)

分析:记dp[i][j]为从i到j合并的最小代价(顺时针,i可以大于j),sum[i][j]为从i到j的和,则dp[i][j]=min{dp[i][k-1]+dp[k][j]}+sum[i][j],(i<k<=j),直接求的话复杂度为O(n^3),会T. 四边形不等式优化:记s[i][j]为dp[i][j]取得最小值时对应的k值,则有dp[i][j]=min{dp[i][k-1]+dp[k][j]}+sum[i][j],(s[i][j-1]<=k<=s[i+1][j]),可以证明,

AC日记——石子归并 51nod 1021

石子归并 思路: 经典动态规划——归并类问题: 我们把状态划为n个,即1-n的n个长度为n个状态: 那么,每个长度为i的状态都可以由i-1个长度为i-1的状态推出: 所以,dp转移方程: dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]); 来,上代码: #include <cstdio> #include <cstring> #include <iostream> #include <algori

51Nod 1021~1023 石子合并 (逐步加强版) 【dp】

51Nod 1021~1023  石子合并 小结: 这里给出三种做法. 第一种:n^3  最基础的合并类dp, f[i,j]=min(f[i,j],f[i,k]+f[k,j]+w[i,j]) 这种代码不贴了,网上多的是.鄙人太弱(逃~) 第二种: n^2  四边形不等式优化... 主要是优化了 k 的枚举, k 从 s[i][j-1] 枚举到 s[i+1][j] 就行了...   ???证明(不会诶,以后再说) 贴代码: 1 #include<bits/stdc++.h> 2 using na