码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-07-15 22:58:40      阅读:170      评论:0      收藏:0      [点我收藏+]

标签:区间dp

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;
}


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

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

标签:区间dp

原文地址:http://blog.csdn.net/kirito_acmer/article/details/46897159

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!