題目描述 Description
有n堆石子排成一列,每堆石子有一個重量w[i], 每次合併可以合併相鄰的兩堆石子,一次合併的代價為兩堆石子的重量和w[i]+w[i+1]。問安排怎樣的合併順序,能夠使得總合並代價達到最小。
輸入描述 Input Description
第一行一個整數n(n<=3000)
第二行n個整數w1,w2...wn (wi <= 3000)
輸出描述 Output Description
一個整數表示最小合併代價
樣例輸入 Sample Input
4
4 1 1 4
樣例輸出 Sample Output
18
資料範圍及提示 Data Size & Hint
資料範圍相比“石子歸併” 擴大了
也沒啥好說的,
就是四邊形不等式優化
證明我也不會
丟個部落格連結
http://blog.csdn.net/noiau/article/details/72514812
#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; }