我是靠谱客的博主 微笑热狗,最近开发中收集的这篇文章主要介绍题解报告:NYOJ #737 石子合并(一)(区间dp),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

描述    

有N堆石子排成一排,每堆石子有一定的数量。现要将N堆石子并成为一堆。合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆。求出总的代价最小值。

输入

有多组测试数据,输入到文件结束。
每组测试数据第一行有一个整数n,表示有n堆石子。
接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开输出输出总代价的最小值,占单独的一行

样例输入

3
1 2 3
7
13 7 8 16 21 4 18

样例输出

9
239
解题思路:经典区间dp!石子合并问题!定义dp[i][j]表示将区间[i,j]合并后得到的最小代价,易想到相邻先两两合并,再三三合并....,直到将整个区间合并完成,dp[1][n]就是要求的最小代价。
状态转移方程为dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]),其中sum[j]-sum[i-1](预处理前缀和)为将区间[i,j]合并得到的代价,k为断点的枚举。时间复杂度为O(n^3)。

AC代码一(340ms):
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=205;
 4 int n,a[maxn],sum[maxn],dp[maxn][maxn];
 5 int main(){
 6
while(~scanf("%d",&n)){
 7
memset(dp,0x3f,sizeof(dp));
 8
memset(sum,0,sizeof(sum));
 9
for(int i=1;i<=n;++i)scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i],dp[i][i]=0;//初始状态dp[i][i]表示当前每一堆的代价为0
10
for(int len=1;len<=n;++len){//区间长度
11
for(int i=1;i<=n-len;++i){//区间起点
12
int j=i+len;//区间终点
13
for(int k=i;k<j;++k)//断点k把(i,j)分成2堆,dp[i][j]为原来两堆各自的代价和再加上合并的两堆得到的代价之和
14
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
15 
}
16 
}
17
printf("%dn",dp[1][n]);
18 
}
19
return 0;
20 }

AC代码二(0ms):GarsiaWachs算法,时间复杂度为0(n^2)。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 using namespace std;
 5 const int maxn=205;
 6 const int inf=0x7fffffff;//2147483647
 7 int n,m,t,ans,stone[maxn];
 8 void dfs(int k){
 9
int tmp=stone[k-1]+stone[k];
10
ans+=tmp;t--;
11
for(int i=k;i<t;++i)stone[i]=stone[i+1];//元素左移,表示删掉了一个元素
12
int j=0;k--;
13
for(j=k;stone[j-1]<tmp;--j)stone[j]=stone[j-1];//元素右移,找到第一个满足条件的j
14
stone[j]=tmp;//将tmp插到j后面
15
while(j>=3&&stone[j-2]<=stone[j]){//继续向前查找是否还有满足条件的情况
16
int d=t-j;//保存当前t离操作点的距离d
17
dfs(j-1);//合并第j-1堆和第j-2堆石子
18
j=t-d;//设置新的操作点j
19 
}
20 }
21 int main(){
22
while(~scanf("%d",&n)){
23
for(int i=1;i<=n;++i)scanf("%d",&stone[i]);
24
t=2,ans=0;stone[0]=stone[n+1]=inf;//左右边界设置成无穷
25
for(int i=2;i<=n;++i){
26
stone[t++]=stone[i];
27
while(t>3&&stone[t-3]<=stone[t-1])dfs(t-2);//表示当前至少有3堆石子,并且满足stone[k-1]<=stone[k+1],其中k=t-2,就合并第t-3和第t-2堆石子
28 
}
29
while(t>2)dfs(t-1);//如果剩下的堆数至少为3-1=2堆,则继续合并,直至剩下一堆石子
30
printf("%dn",ans);
31 
}
32
return 0;
33 }

 

转载于:https://www.cnblogs.com/acgoto/p/9624438.html

最后

以上就是微笑热狗为你收集整理的题解报告:NYOJ #737 石子合并(一)(区间dp)的全部内容,希望文章能够帮你解决题解报告:NYOJ #737 石子合并(一)(区间dp)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(54)

评论列表共有 0 条评论

立即
投稿
返回
顶部