GarsiaWachs算法

題目描述:

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


GarsiaWachs算法具體應用: http://fanhq666.blog.163.com/blog/static/81943426201062865551410/


具體實現方法:

設一個序列是A[0..n-1],每次尋找最小的一個滿足A[k-1]<=A[k+1]的k,那麼我們就把A[k]與A[k-1]合併,之後從k向前尋找第一個滿足A[j]>A[k]+A[k-1]的j,把合併後的值A[k]+A[k-1]插入A[j]的後面。      


舉個例子:
186 64 35 32 103
因爲35<103,所以最小的k是3,我們先把35和32刪除,得到他們的和67,並向前尋找一個第一個超過67的數,把67插入到他後面
186 64(k=3,A[3]與A[2]都被刪除了) 103
186 67(遇到了從右向左第一個比67大的數,我們把67插入到他後面) 64 103
186 67 64 103 (有定理保證這個序列的答案加上67就等於原序列的答案)
現在由5個數變爲4個數了,繼續!
186 (k=2,67和64被刪除了)103
186 131(就插入在這裏) 103
186 131 103
現在k=2(別忘了,設A[-1]和A[n]等於正無窮大)
234 186
420
最後的答案呢?就是各次合併的重量之和唄。420+234+131+67=852,哈哈,算對了。

代碼如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <queue>
#define ri(n) scanf("%d",&n)
#define oi(n) printf("%d\n",n)
#define rl(n) scanf("%lld",&n)
#define ol(n) printf("%lld\n",n)
#define rep(i,l,r) for(i=l;i<=r;i++)
#define rep1(i,l,r) for(i=l;i<r;i++)
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int epg=10-8;
int a[50000+10];
ll ans;
int t;
void dfs(int k)
{
    int tmp=a[k-1]+a[k];
    ans+=tmp;
    for(int i=k;i<t-1;i++)
        a[i]=a[i+1];
    t--;
    int j;
    for(j=k-1;j>0&&a[j-1]<tmp;j--)
        a[j]=a[j-1];
    a[j]=tmp;
    while(j>=2&&a[j]>=a[j-2])
    {
        int d=t-j;
        dfs(j-1);
        j=t-d;
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    t=1;
    ans=0;
    for(int i=1;i<n;i++)
    {
        a[t++]=a[i];
        while(t>=3&&a[t-3]<=a[t-1])
            dfs(t-2);
    }
    while(t>1)
        dfs(t-1);
    printf("%lld\n",ans);
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章