題目鏈接:https://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Index/problemdetail/pid/1977.html
四邊形不等式優化dp
學習博客:https://blog.csdn.net/noiau/article/details/72514812
環形排列 N 堆石子。現要將石子有次序地合併成一堆。規定每次只能選相鄰的 2 堆石子合併成新的一堆,並將新的一堆石子數記爲該次合併的得分。求 N 堆石子合併成一堆的最小得分。
(其實還有NlogN的做法)
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define mp make_pair
#define pb push_back
#define ls (o<<1)
#define rs (o<<1|1)
#define ll long long
using namespace std;
const int N = 10010;
int n,m,s[N],dp[N][N],sum[N],pos[N][N];
int oper;
int main() {
// freopen("a.txt","r",stdin);
ios::sync_with_stdio(0);
cin>>n;
rep(i, 1, n) cin>>s[i];
rep(i, n+1, 2*n) s[i] = s[i-n];
rep(i, 1, 2*n) sum[i] = sum[i-1] + s[i];
n*=2;
rep(i, 1, n) dp[i][i] = 0,pos[i][i] = i;
per(i, n, 1)
rep(j, i+1, n) {
int ans = 1e9;
int mk = -1;
rep(k, pos[i][j-1],pos[i+1][j]) {
if(ans > dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]) {
ans = dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
mk = k;
}
}
dp[i][j] = ans;
pos[i][j] = mk;
}
int ans = 1e9;
rep(i, 1, n/2) ans = min(ans,dp[i][i+n/2-1]);
cout<<ans;
return 0;
}