1. 程式人生 > >石子歸併 (四邊形不等式優化

石子歸併 (四邊形不等式優化

石子歸併 (四邊形不等式優化

感覺很有 不靠譜 道理
顯然樸素演算法是\(O(n^3)\)
\(f[i][j]\)表示i到j花費的最小价值
\(f[i][j] = min(f[i][k - 1] + f[k][j] + sum[j] - sum[i - 1])\)
通過打表打出中間點K的方式
我們會發現
\(K[i][j - 1] <= K[i][j] <= K[i + 1][j]\)
然後複雜度就降到\(O(n^2)\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#define rep(i , x, p) for(int i = x;i <= p;++ i)
#define sep(i , x, p) for(int i = x;i >= p;-- i)
#define gc getchar()
#define pc putchar
#define ll long long
using std::min;
using std::max;
using std::swap;
const int maxN = 10000 + 7;
using namespace std;

int f[maxN][maxN] , K[maxN][maxN];
int sum[maxN] , a[maxN];

inline int gi() {int x = 0,f = 1;char c = gc;while(c < '0' || c > '9') {if(c == '-')f = -1;c = gc;}while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = gc;}return x * f;}
void print(ll x) {if(x < 0) pc('-') , x = -x;if(x >= 10) print(x / 10);pc(x % 10 + '0');}

int main() {
    memset(f , 0x3f, sizeof(f));
    int n = gi();
    rep(i , 1, n) a[i] = gi();
    rep(i , 1, n) sum[i] = sum[i - 1] + a[i];
    rep(i , 1, n) f[i][i] = 0 , K[i][i] = i;
    rep(len , 1, n) {
        rep(i , 1, n) {
            if(i + len > n) break;
            int j = i + len;
            int l = K[i][j - 1] , r = K[i + 1][j] , k , qw;
            for(k = l;k <= r;++ k) {
                if(f[i][j] > f[i][k - 1] + f[k][j] + sum[j] - sum[i - 1]) {
                    f[i][j] = f[i][k - 1] + f[k][j] + sum[j] - sum[i - 1];
                    qw = k;
                }
            }
            K[i][j] = qw;
        }
    }
    printf("%d",f[1][n]);
    return 0;
}