释放第一个囚犯的过程就是把整个区间分成两个子区间的过程,代价是两边人数和。而对于新形成的两个子区间,又可以按照类似方法实现划分。那么完全可以把整个过程倒过来,通过小区间合并来形成最终大区间即可。
预处理出来m个人分出来的m+1个区间,这些区间并不包含释放的人,我们枚举断点的时候还要算上断点之外,区间之外的人,也就是大区间拆分时还没释放的人;
#include <iostream>
# include<algorithm>
using namespace std;
typedef long long int ll;
int sum[1010],a[1010],dp[1010+10][1010+10];
int n,m;
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>a[i];
}
m++;
a[m]=n+1;
for(int i=1;i<=m;i++)
{
sum[i]=sum[i-1]+a[i]-a[i-1]-1;
}
for(int i=1;i<=1010;i++)
{
for(int j=1;j<=1010;j++)
{
if(i!=j)
dp[i][j]=9999999;
}
}
for(int len=2;len<=m;len++)
{
for(int i=1;i+len-1<=m;i++)
{
int j=i+len-1;
for(int k=i;k<j;k++)
{
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]+j-i-1);
}
}
}
cout<<dp[1][m];
return 0;
}