cqyz oj/洛谷 | 释放囚犯 | 区间DP

题目描述

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;
}
posted @ 2020-01-19 11:22  Deguassing-compass  阅读(123)  评论(0编辑  收藏  举报