問題描述:
給定n個整數組成的序列,現在要求將序列分割為m段,每段子序列中的數在原序列中連續排列。如何分割才能使這m段子序列的和的最大值達到最小?
輸入格式:
第一行給出n,m,表示有n個數分成m段,隨后一行給出n個數,以空格分隔
輸入樣例:
9 3
9 8 7 6 5 4 3 2 1
輸出樣例:
17
解釋:
9 8 | 7 6 | 5 4 3 2 1,9個數分成3段所有情況里這種分法的最大子段和(17)最小。
思路:
動態規划的一種模板,包括矩陣連乘,石子歸並等問題。先是考慮分的段數,然后考慮起點/終點,最后是每段中分割點的位置。
本題中使用 dp[i][j]表示前i個數分成j段里最小的最大子段和,則dp[i][j]=min{dp[i][1]-dp[k][1],dp[k][j-1] (1<=k<i)};
代碼:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 99 4 #define inf 0x3f3f3f3f 5 int a[N],dp[N][N];//dp[i][j]表示前i個數分j段所有情況里最大子段和最小的 6 int main() 7 { 8 int n,m; 9 cin>>n>>m; 10 for(int i=1; i<=n; i++) 11 cin>>a[i]; 12 for(int i=1; i<=n; i++) 13 dp[i][1]=dp[i-1][1]+a[i]; 14 for(int r=2; r<=m; r++){ 15 for(int i=1; i<=n; i++){ 16 int mins=inf; 17 for(int k=1; k<i; k++){ 18 int t=max(dp[i][1]-dp[k][1],dp[k][r-1]); 19 if(t<mins) mins=t; 20 } 21 dp[i][r]=mins; 22 } 23 } 24 cout<<dp[n][m]; 25 return 0; 26 }