您的位置:首页 > 其它

GarsiaWachs算法:石子归并问题

2016-10-06 22:31 302 查看
1023 石子归并 V3


基准时间限制:2 秒 空间限制:131072 KB 分值: 320 难度:7级算法题


 收藏


 关注

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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: