zjnu1181 石子合并【基础算法?动态规划】——高级

Description

在操场上沿一直线排列着

n堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆石子合并成新的一堆,

并将新的一堆石子数记为该次合并的得分。允许在第一次合并前对调一次相邻两堆石子的次序。

计算在上述条件下将n堆石子合并成一堆的最小得分。

Input

输入数据共有二行,其中,第1行是石子堆数n≤100;

第2行是顺序排列的各堆石子数(≤20),每两个数之间用空格分隔。

Output

输出合并的最小得分。

Sample Input


3
2 5 1

Sample Output



11

第一道区间dp,这题设一个数组dp[i][j]表示从i取到j的最小得分。

状态转移方程:dp[i][i+len]=min(dp[i][i+len],dp[i][i+len1]+dp[i+len1+1][i+len]+sum[i+len]-sum[i-1]);这里注意所有的dp[i][i]为0,因为只有一个数的时候不用合并,所以是0。因为题目允许第一次开始取的时候相邻数字能搞交换,所以外面加个循环,同时每次的sum[],dp[i][i+1]都要重新初始化。另外,这题用四边形优化会大大加快速度。
#include<stdio.h>
#include<string.h>
#define inf 88888888
int min(int a,int b){
	return a<b?a:b;
}
int a[106],dp[106][106],sum[106];
int main()
{
	int n,m,i,j,temp,len,sum1,ans,len1,k;
	while(scanf("%d",&n)!=EOF)
	{
		for(i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		sum1=inf;
		for(k=1;k<=n-1;k++){
			temp=a[k];
			a[k]=a[k+1];
			a[k+1]=temp;
			memset(sum,0,sizeof(sum));
			memset(dp,inf,sizeof(dp));
			for(i=1;i<=n-1;i++){
				sum[i]=sum[i-1]+a[i];
				dp[i][i+1]=a[i]+a[i+1];dp[i][i]=0;
			}
			dp[n][n]=0;sum[n]=sum[n-1]+a[n];
			for(len=2;len<=n-1;len++){
				for(i=1;i+len<=n;i++){
					for(len1=0;len1<len;len1++){
						dp[i][i+len]=min(dp[i][i+len],dp[i][i+len1]+dp[i+len1+1][i+len]+sum[i+len]-sum[i-1]);
					}
				}
			}
			temp=a[k];
			a[k]=a[k+1];
			a[k+1]=temp;
			if(dp[1][n]<sum1)sum1=dp[1][n];
		}
	    printf("%d\n",sum1);
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-28 23:07:30

zjnu1181 石子合并【基础算法?动态规划】——高级的相关文章

zjnu(1183)——括号序列【基础算法?动态规划】——高级

首先,我只想声明一点,这道题有毒...我用char读入就错了,然而换成string读入就对了或者可以把定义char的数组开的大一点,原先1A的一题硬是纠结了老半天. 传送门:zjnu 题意: 就是对于一个组成的序列,添加尽量少的括号得到一个规则序列,并且输出这个序列的长度. 不过我学到了两种定义dp状态的方法: 1)定义dp[i][j]为i~j中需要添加的最少的括号数.这里我们记录s为一段字符的开始位置,e为一段字符的结束位置. ①当(a[s]=='('&&a[e]==')')||(a[s

CH5301 石子合并【区间dp】

5301 石子合并 0x50「动态规划」例题 描述 设有N堆沙子排成一排,其编号为1,2,3,-,N(N<=300).每堆沙子有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆,每次只能合并相邻的两堆,合并的代价为这两堆沙子的数量之和,合并后与这两堆沙子相邻的沙子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同,如有4堆沙子分别为 1  3  5  2 我们可以先合并1.2堆,代价为4,得到4 5 2 又合并 1,2堆,代价为9,得到9 2 ,再合并得到11,总代价为

算法温习动态规划之石子合并问题

石子合并问题分为直线型和圆形: 直线型: 直线型狮子合并问题存在以下递推式: f[i][j]:表示从第i堆合并到底j堆,最少代价 f[i][j]=0;     i=j f[i][j]=min( f[i][k]+f[k+1][j]+sum(i,j));       i<=k<j; 这个问题比较好理解,根据递推式,我们的i要从高到底遍历,j要从低到高遍历 直线型代码如下: #include<iostream> #include<vector> using namespace

动态规划思想:石子合并问题

描述:在一个圆形操场的四周摆放着n 堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分.试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分. 贪心算法不能得到最优解,可惜了.首先我们可以把这么堆石子看成一列 如果N-1次合并的全局最优解包含了每一次合并的子问题的最优解,那么经这样的N-1次合并后的得分总和必然是最优的.因此我们需要通过动态规划算法来求出最优解. 在此我们假设有n堆石子,一字排开,合并相邻两堆的石子,

合并类动态规划——石子合并

题目描述 Description 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分.试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分. 输入输出格式 Input/output 输入格式:数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.输出格式:输出共2行,第1行为最小得分,第2行为最大得分. 输入输出样例 Sample input/out

石子合并的动态规划问题

题目大概都是这样的: 设有N堆沙子排成一排,其编号为1,2,3,-,N(N<=300).每堆沙子有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆,每次只能合并相邻的两堆,合并的代价为这两堆沙子的数量之和,合并后与这两堆沙子相邻的沙子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同,如有4堆沙子分别为 1  3  5  2 我们可以先合并1.2堆,代价为4,得到4 5 2 又合并 1,2堆,代价为9,得到9 2 ,再合并得到11,总代价为4+9+11=24,如果第二步

【dp】关于石子合并的O(nlogn)做法 GarsiaWachs算法

P5569 题意: 在一个操场上摆放着一排 \(N\) 堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的 \(2\) 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分. 试设计一个算法,计算出将 \(N\) 堆石子合并成一堆的最小得分. 数据范围: \(N≤40000,a_i≤200\) 题解: \(GrasiaWachs\) 算法 从左往右找,找到第一个 \(k\) ,使得 \(a[k-1]<=a[k+1]\) ,我们把这两堆石子合并,把代价加在 \(sum\) 上 然后从

动态规划—石子合并(直线和环)

先来看直线的: 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) =>

石子合并问题(一) (基础的区间dp)

石子合并(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述     有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价最小值. 输入 有多组测试数据,输入到文件结束. 每组测试数据第一行有一个整数n,表示有n堆石子. 接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开 输出 输出总代价的最小值,