题目描述
Caima王国中有一个奇怪的监狱,这个监狱一共有P个牢房,这些牢房一字排开,第i个紧挨着第i+1个(最后一个除外)。现在正好牢房是满的。
上级下发了一个释放名单,要求每天释放名单上的一个人。这可把看守们吓得不轻,因为看守们知道,现在牢房中的P个人,可以相互之间传话。如果某个人离开了,那么原来和这个人能说上话的人,都会很气愤,导致他们那天会一直大吼大叫,搞得看守很头疼。如果给这些要发火的人吃上肉,他们就会安静点。
输入格式
第一行两个数P和Q,Q表示释放名单上的人数;
第二行Q个数,表示要释放哪些人。
数据规模
对于100%的数据1≤P≤1000; 1≤Q≤100;Q≤P;且50%的数据 1≤P≤100;1≤Q≤5
输出格式
仅一行,表示最少要给多少人次送肉吃。
输入 1
20 3
3 6 14
输出 1
35
【样例说明】
先释放14号监狱中的罪犯,要给1到13号监狱和15到20号监狱中的19人送肉吃;再释放6号监狱中的罪犯,要给1到5号监狱和7到13号监狱中的12人送肉吃;最后释放3号监狱中的罪犯,要给1到2号监狱和4到5号监狱中的4人送肉吃。
设f[i][j]表示释放区间[i,j]的犯人需要的最小花费(其中i,j是要被释放的犯人,即下面的a[]的序号,不是监狱的序号)。
方程:
[f[i][j]=min{f[i][k]+f[k+1][j]+a[j+1]-a[i-1]-1-1}a[j+1]-a[i-1]-1
]
就是这次释放的区间的人数,再-1是因为被放出去的那个囚犯不需要吃肉
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 105;
int p, q;
int f[maxn][maxn], a[maxn];
int main(){
scanf("%d%d",&p,&q);
for(int i=1;i<=q;i++)scanf("%d",&a[i]);
sort(a+1,a+1+q);//有序才能转移
a[0] = 0;a[q+1] = p+1;//将0和q+1看成有人便于转移
for(int len=1; len <= q; len++){//按区间长度dp
for(int i=1; i+len-1 <= q; i++){
int j = i+len-1;
f[i][j] = 0x3f3f3f3f;
for(int k=i;k<=j;k++)//省略了初始化f[i][i-1]为0
f[i][j] = min(f[i][j], f[i][k-1]+f[k+1][j]+a[j+1]-a[i-1]-1-1);
}
}
printf("%d", f[1][q]);
return 0;
}