記錄一下,以避免忘了html
對於一個形如
\[dp[i][j]=min(dp[i][k]+dp[k][j]+w[i][j])\]
的轉移方程(注意取最大值時不必定知足四邊形不等式)算法
若對於\(a \leq b\leq c \leq d\)且\(w_{b,c}\leq w_{a,d}\)
那麼咱們稱\(w\)關於區間包含關係單調
spa
若對於\(a \leq b\leq c \leq d\)且\(w_{a,c}+w_{b,d}\leq w_{b,c}+w_{a,d}\)
則稱\(w\)知足四邊形不等式
.net
若\(w\)知足四邊形不等式,當且僅當\(w_{i,j}+w_{i+1,j+1}\leq w_{i+1,j}+w_{i,j+1}\)
(沒啥卵用)code
若\(w\)知足四邊形不等式,且關於區間包含關係單調
則\(dp\)也知足四邊形不等式htm
設\(s_{i,j}\)爲\(dp_{i,j}\)的決策點,若\(dp\)知足四邊形不等式
那麼\(s_{i,j-1}\leq s_{i,j} \leq s_{i+1,j}\)blog
放一個不錯的博客get
石子歸併增強版
其實這題並非極限數據,再強一點的能夠去百度SDOI2008石子歸併,聽說要用平衡樹維護某G姓算法博客
#include<cstdio> #include<cstring> const int MAXN=1e5+10,INF=1e8+10; using namespace std; inline char nc() { static char buf[MAXN],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin)),p1==p2?EOF:*p1++; } inline int read() { char c=nc();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=nc();} return x*f; } int dp[3001][3001],sum[MAXN],s[3001][3001]; int main() { #ifdef WIN32 freopen("a.in","r",stdin); #else #endif int N=read(); for(int i=1;i<=N;i++) sum[i]=read(),sum[i]+=sum[i-1],s[i][i]=i; for(int i=N;i>=1;i--) { for(int j=i+1;j<=N;j++) { int mn=INF,mnpos=0; for(int k=s[i][j-1];k<=s[i+1][j];k++) { if(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1] < mn) { mn=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]; mnpos=k; } } dp[i][j]=mn; s[i][j]=mnpos; } } printf("%d",dp[1][N]); return 0; }