* *

时间:2022-06-11 09:33:08

【题目描述】
Caima 王国中有一个奇怪的*,这个*一共有 P 个牢房,这些牢房一字排开,
第 i 个仅挨着第 i+1 个(最后一个除外)。现在正好牢房是满的。
上级下发了一个释放名单,要求每天释放名单上的一个人。这可把看守们吓得不
轻,因为看守们知道,现在牢房中的 P 个人,可以互相之间传话。如果某个人离开了,
那么原来和这个人能说上话的人,都会很气愤,导致他们那天会一直大吼大叫,搞得
看守很头疼。如果给这些要发火的人吃上肉,他们就会安静点。
现在看守们想知道,如何安排释放的顺序,才能使得他们花费的肉钱最少。
【输入格式】
第一行两个数 P 和 Q,Q 表示释放名单上的人数;
第二行 Q 个数,表示要释放哪些人。
【输出格式】
仅一行,表示最少要给多少人次送肉吃。
【数据规模】
1<=P<=1000;1<=Q<=100。
【输入样例】
20 3
3 6 14
【输出样例】
35
【注意事项】
Q<=P;且 50%的数据 1<=P<=100;1<=Q<=5。

区间dp

令f[i][j]表示释放了i~j的最小费用

f[i][j]=min(f[i][k-1]+f[k+1][j]+(a[j+1]-a[i-1]))

其实是一个逆推的过程

我们从结果f[i][i]一步步推到f[1][q]

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int a[],p,q,f[][];
int main()
{int i,j,k,s=;
cin>>p>>q;
for (i=;i<=q;i++)
{
scanf("%d",&a[i]);
}
a[q+]=p+;a[]=;
memset(f,/,sizeof(f));
for (i=;i<=q;i++)
f[i][i]=a[i+]-a[i-]-;
for (i=;i<=q;i++)
{
for (j=;j+i-<=q;j++)
{
for (k=j;k<=j+i-;k++)
{
s=;
if (k>=j+)
s+=f[j][k-];
if (k<j+i-)
s+=f[k+][j+i-];
s+=a[j+i]-a[j-]-;
f[j][j+i-]=min(f[j][j+i-],s);
}
}
}
cout<<f[][q];
}