GarsiaWachs算法:石子归并问题
2016-10-06 22:31
302 查看
1023 石子归并 V3
![](http://file.51nod.com/images/icon/ok.png)
基准时间限制:2 秒 空间限制:131072 KB 分值: 320 难度:7级算法题
![](http://file.51nod.com/images/icon/star.png)
收藏
![](http://file.51nod.com/images/icon/plus.png)
关注
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
Output
Input示例
Output示例
问题分析:
如果只有3堆石子,那么只有两种合并方法,它们的代价为s1、s2,那么有
s1 = (a+b)+((a+b)+c)
s2 = (b+c)+((b+c)+a)
假设s1<s2, 那么可以得出a<=c, 这说明只要a和c的关系确定,合并的顺序也确定
①:GarsiaWachs算法,就是基于上述的结论实现,找出序列中满足stone[i-1]<=stone[i+1]最小的i,
先合并temp = stone[i-1]+stone[i], 然后往前面找第一个满足stone[j]>temp的地方,(或找不到)
最后把temp值插入stone[j]的后面,循环这个过程直到只剩下一堆石子结束
②:为什么要将temp插入stone[j]的后面?可以这样理解:将stone[j+1]到stone[i-2]
看成一个整体stone[mid],这样状态就为stone[j],stone[mid],temp(stone[i-1]+stone[i]);
因为temp<stone[j],所以不管怎样都是stone[mid]和temp先合并,所以将temp值插入stone[j]的后面不会影响结果
解题过程:
①:从1到n遍历一遍数组,每当添加一个数时,如果当前最顶端的三个数a,b,c满足a<c,则执行操作③合并a和b,执行完毕后如果依旧如此继续执行操作③直到最顶端的三个数不满足条件a<c
②:遍历完毕后,如果剩下的数不止一个,执行操作③合并当前最顶端的两个直到只剩下一个数
③:合并a和b,令temp=a+b,先将a和b从数组中取出,然后将a右边的数全部往左移1位,将a左边所有小于temp的数全部往右移1位,最后在空位处补上temp,设temp所在位置为i,处理完毕后可能再次出现a[i-2]<a[i],如果出现继续执行步骤③将a[i-2]和a[i-1]合并,直到不满足当前a[i-2]<a[i]
![](http://file.51nod.com/images/icon/ok.png)
基准时间限制:2 秒 空间限制:131072 KB 分值: 320 难度:7级算法题
![](http://file.51nod.com/images/icon/star.png)
收藏
![](http://file.51nod.com/images/icon/plus.png)
关注
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 <= 50000) 第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)
Output
输出最小合并代价
Input示例
4 1 2 3 4
Output示例
19
问题分析:
如果只有3堆石子,那么只有两种合并方法,它们的代价为s1、s2,那么有
s1 = (a+b)+((a+b)+c)
s2 = (b+c)+((b+c)+a)
假设s1<s2, 那么可以得出a<=c, 这说明只要a和c的关系确定,合并的顺序也确定
①:GarsiaWachs算法,就是基于上述的结论实现,找出序列中满足stone[i-1]<=stone[i+1]最小的i,
先合并temp = stone[i-1]+stone[i], 然后往前面找第一个满足stone[j]>temp的地方,(或找不到)
最后把temp值插入stone[j]的后面,循环这个过程直到只剩下一堆石子结束
②:为什么要将temp插入stone[j]的后面?可以这样理解:将stone[j+1]到stone[i-2]
看成一个整体stone[mid],这样状态就为stone[j],stone[mid],temp(stone[i-1]+stone[i]);
因为temp<stone[j],所以不管怎样都是stone[mid]和temp先合并,所以将temp值插入stone[j]的后面不会影响结果
解题过程:
①:从1到n遍历一遍数组,每当添加一个数时,如果当前最顶端的三个数a,b,c满足a<c,则执行操作③合并a和b,执行完毕后如果依旧如此继续执行操作③直到最顶端的三个数不满足条件a<c
②:遍历完毕后,如果剩下的数不止一个,执行操作③合并当前最顶端的两个直到只剩下一个数
③:合并a和b,令temp=a+b,先将a和b从数组中取出,然后将a右边的数全部往左移1位,将a左边所有小于temp的数全部往右移1位,最后在空位处补上temp,设temp所在位置为i,处理完毕后可能再次出现a[i-2]<a[i],如果出现继续执行步骤③将a[i-2]和a[i-1]合并,直到不满足当前a[i-2]<a[i]
#include<stdio.h> #define LL long long LL a[50005], n, k, ans; void Combine(LL x); int main(void) { LL i; scanf("%lld", &n); for(i=1;i<=n;i++) scanf("%lld", &a[i]); k = 1, ans = 0; for(i=2;i<=n;i++) { a[++k] = a[i]; while(k>=3 && a[k-2]<=a[k]) /*①*/ Combine(k-2); /*合并a[k-2], a[k-1]*/ } while(k>1) /*②*/ Combine(k-1); printf("%lld\n", ans); return 0; } void Combine(LL x) /*③*/ { LL i, d, temp; temp = a[x]+a[x+1]; for(i=x+1;i<=k-1;i++) a[i] = a[i+1]; ans += temp, k -= 1; for(i=x-1;i>=1&&a[i]<=temp;i--) a[i+1] = a[i]; a[i+1] = temp; while(i>=2 && a[i-1]<=a[i+1]) { d = k-i; Combine(i-1); i = k-d; } }
相关文章推荐
- poj1738 An old Stone Game 【GarsiaWachs算法】【动态规划】经典合并石子问题
- 51 nod 1023 石子归并 V3(GarsiaWachs算法)
- [其它-GarsiaWachs算法]51nod 1023 石子归并v3
- [GarsiaWachs算法] BZOJ 3229 [Sdoi2008]石子合并 & POJ 1738 An old Stone Game & 51Nod 1023 石子归并 V3
- [其它-GarsiaWachs算法]51nod 1023 石子归并v3
- 用01背包解决石子归并问题
- 石子合并问题 (朴素区间DP&&GarsiaWachs算法)
- 51 NOD 1021 石子归并(二维dp,GarsiaWachs算法)
- 石子归并问题
- 【题解】环形石子归并问题
- 石子归并(GarsiaWachs算法)
- 石子归并问题(codevs 1048)
- 51Nod-石子归并问题(DP解法)
- 区间DP入门之 石子归并问题
- 经典问题二.【区间dp】石子归并 51nod 1021
- 石子归并问题
- NYOJ 737---石子归并(GarsiaWachs算法)
- 51 NOD 1023 石子归并 V3(GarsiaWachs算法)
- poj1738 An old Stone Game 石子合并(归并) GarsiaWachs算法
- 石子归并问题(nyoj737)