1. 程式人生 > >四邊形不等式(石子合並)

四邊形不等式(石子合並)

石子合並 i+1 col 區間 sum style log n) sca

動態規區間dp做這道題的話應該是n^3,下面的代碼優化到了n^2,用四邊形不等式優化。

設mid[i][j]是dp[i][j]的最優解的斷點,即它左區間的右端點,那麽mid[i][j-1]<=mid[i][j]<=mid[i+1][j],所以在求解dp[i][j]時,枚舉k可以只枚舉這兩個值之間枚舉就好,

程序要先枚舉區間長度,在枚舉左端點,枚舉每個區間長度時,他們的k總是只從1到n,只走一遍,所以這就相當於優化了一層,變成了O(n2)的。

比如len長度為3時,dp[1][3]只會枚舉mid[1][2]-mid[2][3],如上。然後dp[2][4]時,枚舉mid[2][3]-mid[3][4]。以此類推。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int MAXN = 4010;
 5 const int INF = 1e8;
 6 int dp[MAXN][MAXN],a[MAXN],sum[MAXN],mid[MAXN][MAXN],n;
 7 
 8 int main()
 9 {
10     scanf("%d",&n);
11     for (int i=1; i<=n; ++i)
12         scanf("
%d",&a[i]), sum[i] = sum[i-1]+a[i]; 13 14 for (int i=1; i<=n; ++i) 15 dp[i][i] = 0, mid[i][i] = i; 16 17 for (int len=1; len<n; ++len)//求右端點(i+len-1)會減1,先在這減了 18 { 19 for (int i=1; i<=n-len; ++i)//左端點i最大值是右端點等於n時,(i+len)=n,i=n-len 20 {
21 int j = i+len;//右端點 22 dp[i][j] = INF; 23 for (int k=mid[i][j-1]; k<=mid[i+1][j]; ++k) 24 { 25 if (dp[i][j]>dp[i][k]+dp[k+1][j]) 26 { 27 dp[i][j] = dp[i][k]+dp[k+1][j]; 28 mid[i][j] = k; 29 } 30 } 31 dp[i][j] += sum[j]-sum[i-1]; 32 } 33 } 34 printf("%d",dp[1][n]); 35 return 0; 36 }

四邊形不等式(石子合並)