P1622 释放囚犯-动态规划,区间dp

版权声明:原创,勿转 https://blog.csdn.net/qq_42386465/article/details/82759054

Caima王国中有一个奇怪的监狱,这个监狱一共有P个牢房,这些牢房一字排开,第i个紧挨着第i+1个(最后一个除外)。现在正好牢房是满的。

上级下发了一个释放名单,要求每天释放名单上的一个人。这可把看守们吓得不轻,因为看守们知道,现在牢房中的P个人,可以相互之间传话。如果某个人离开了,那么原来和这个人能说上话的人,都会很气愤,导致他们那天会一直大吼大叫,搞得看守很头疼。如果给这些要发火的人吃上肉,他们就会安静点。

输出最少要给多少人送肉吃。

首先不难想到要用dp,看到一字排开,还要求最少给多少个人送肉吃,这就区间dp了啊。

区间dp的套路:设f[i][j]为区间释放i~j号囚犯所需最少的肉(注意,i,j不是牢房编号,是释放的囚犯编号,也就是下面的a[i]数组)

f[i][j]=min{f[i][j],f[i][k-1]+f[k+1][j]+a[j+1]-a[i-1]-1-1}

用a[j+1]-a[i-1]-1表示i到j之间要喂多少块肉,然后枚举断点k,也就是那个要被释放的人,再-1是因为这个人被释放了就不需要再给肉了。

套路:枚举区间长度,枚举左端点,求出右端点,枚举断点;

https://www.luogu.org/problemnew/show/P1622

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m;
int q[1001];
int f[1001][1001];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        cin>>q[i];
    }
    sort(q+1,q+m+1);
    q[0]=0;q[m+1]=n+1;
    for(int l=1;l<=m;l++){
        for(int i=1;i+l-1<=m;i++){
            int j=i+l-1;
            f[i][j]=0x3f3f;
            for(int k=i;k<=j;k++){
                f[i][j]=min(f[i][j],f[i][k-1]+f[k+1][j]+q[j+1]-q[i-1]-1-1);
            }
        }
    }
    printf("%d",f[1][m]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42386465/article/details/82759054