问题描述:
给定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)};
代码:
#include<bits/stdc++.h> using namespace std; #define N 99 #define inf 0x3f3f3f3f int a[N],dp[N][N];//dp[i][j]表示前i个数分j段所有情况里最大子段和最小的 int main() { int n,m; cin>>n>>m; for(int i=1; i<=n; i++) cin>>a[i]; for(int i=1; i<=n; i++) dp[i][1]=dp[i-1][1]+a[i]; for(int r=2; r<=m; r++){ for(int i=1; i<=n; i++){ int mins=inf; for(int k=1; k<i; k++){ int t=max(dp[i][1]-dp[k][1],dp[k][r-1]); if(t<mins) mins=t; } dp[i][r]=mins; } } cout<<dp[n][m]; return 0; }