石子合併——區間dp
阿新 • • 發佈:2022-03-28
所有的區間dp問題列舉時,第一維通常是列舉區間長度,並且一般 len = 1 時用來初始化,列舉從 len = 2 開始;第二維列舉起點 i (右端點 j 自動獲得,j = i + len - 1)
這就是典型的區間dp問題。因為求的是1到n的代價最小值,所以我們可以先一般化,最後再得出特殊的1到n的代價。
狀態表示:區間【i,j】的代價總和的最小值。
對於區間【i,j】,我們可以細化分為【i,k】與【k+1,j】的合併項,其中k的範圍是大於等於i,小於j。
狀態計算:
1.如果i==j,則f [ i , j ] 初始化為0
2.如果i!= j,則f [ i , j ] = min( f [ i ] [ k ] + f [k +1 ][ j ] + s[ j ] - s [ i -1 ] )
其中s[ j ] - s [ i -1 ]是從i到j的代價字首和相減得到的最後一次兩堆石子合併的代價和
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=350; 4 int a[N],f[N][N],s[N]; 5 6 int main() 7 { 8 int n;scanf("%d",&n); 9 for(int i=1;i<=n;i++) 10 { 11 scanf("%d",&a[i]); 12 s[i]=s[i-1View Code]+a[i]; 13 } 14 15 for(int len=1;len<=n;len++) 16 { 17 for(int i=1;i+len-1<=n;i++) 18 { 19 int j=i+len-1; 20 if(i==j) //初始化 21 { 22 f[i][j]=0; 23 continue; 24 } 25 f[i][j]=0x3f3f3f3f; //初始化 26 for(int k=i;k<j;k++) 27 { 28 f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]); 29 } 30 } 31 } 32 33 printf("%d\n",f[1][n]); 34 35 return 0; 36 }