石子合并DP

DP

Time Limit:3000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu

Description

  桌上有一排 N 堆饭团。现要将饭团合并成一堆。规则是
每次只能选相邻的  2  堆饭团合并成新的一堆,并将新的一堆饭团数记为这次操作的分数。
  将 N 堆饭团合并成一堆的最小总分。

Input

  第一行N(N<=40000) 。
  以下 每行一个数 x(x<=200)  ,表示饭团数目。

Output

  输出最小总分。

Sample Input

4
1
1
1
1

Sample Output

8



//只能 Garsiawachs 解,因为数据很大,时间,空间,一般 DP 都不行
代码看了别人的,代码不难,但是原理难啊,看了很久都不懂。。。先放放,学了哈夫曼树再看看
82ms
 1 //GarsiaWachs算法 0ms
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdio>
 5 using namespace std;
 6 
 7 const int N = 40005;
 8 int stone[N];
 9 int n,t,ans;
10 
11 void combine(int k);
12 
13 int main()
14 {
15     while(cin>>n)
16     {
17         for(int i=0;i<n;i++)
18             scanf("%d",stone+i);
19         t = 1;
20         ans = 0;
21         for(int i=1;i<n;i++)
22         {
23             stone[t++] = stone[i];
24             while(t >= 3 && stone[t-3] <= stone[t-1])
25                 combine(t-2);
26         }
27         while(t > 1)//大于1堆,从最右边那堆开始向左合并
28             combine(t-1);
29         printf("%d
",ans);
30     }
31     return 0;
32 }
33 void combine(int k)
34 {
35     int tmp = stone[k] + stone[k-1];
36     ans += tmp;
37     for(int i=k;i<t-1;i++)//后面的往前移,移到位置 k
38         stone[i] = stone[i+1];
39     t--;
40 
41     int j = 0;
42     for(j=k-1;j>0 && stone[j-1] < tmp;j--)//厉害了,不断往前移坑,
43         stone[j] = stone[j-1];
44     stone[j] = tmp;//填坑
45 
46     while(j >= 2 && stone[j] >= stone[j-2])//如果调整后,又比前2个大,即又是那个条件达成了
47     {
48         int d = t - j;//记录与堆数的差值
49         combine(j-1);
50         j = t - d;//少了几堆就向前移动了几次,位置也变为几
51     }
52 }
View Code
 


原文地址:https://www.cnblogs.com/haoabcd2010/p/6048045.html