护卫小队 题解

二、思路:

这是一道经典DP题。

首先需要注意的是如果我们选了一些小猪,那么这些猪在最终的位置和原来的相对位置是相同的。

设f[i][j][p],表示当前处理到第i只猪,选了j只猪作为护卫,花费了p步。

\[f[i][j][p]=min(f[i-1][j][p],f[i-1][j-1][p-(i-j)]+a[i]) \]

前面的表示不选第i只猪,后面的表示选第i只猪。

时间复杂度\(O(n^4)\)。由于本题时限3s,可以接受。

但注意到空间开不下,用滚动数组优化。

代码有些细节需要注意,具体看代码。

三、代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

#define LL long long
#define FILEIN(s) freopen(s".in","r",stdin)
#define FILEOUT(s) freopen(s".out","w",stdout)
#define mem(s,v) memset(s,v,sizeof(s))

using namespace std;
inline LL read(void){
	LL x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}

const int maxn=155;

int n,K,s;

int a[maxn],ans=0x3f3f3f3f;

int f[maxn][maxn*maxn],g[maxn][maxn*maxn];

int main(){
    n=read();K=read();s=read();
    for(register int i=1;i<=n;++i){
        a[i]=read();
    }
    if(s>=n*(n-1)/2){
        sort(a+1,a+n+1);
        for(register int i=1;i<=K;++i){
            ans+=a[i];
        }
        printf("%d\n",ans);
        return 0;
    }
    mem(g,0x3f);
    for(register int p=0;p<=n*(n-1)/2;++p)g[0][p]=0;
    for(register int i=1;i<=n;++i,swap(f,g)){//滚动数组
        mem(f,0x3f);
        for(register int j=0;j<=i;++j){
            for(register int p=0;p<=i*(i-1)/2;++p){
                f[j][p]=g[j][p];
                if(j&&p>=i-j)f[j][p]=min(f[j][p],g[j-1][p-(i-j)]+a[i]);
            }
        }
    }
    for(register int p=0;p<=s;++p)ans=min(ans,g[K][p]);
    printf("%d\n",ans);
	return 0;
}

posted @ 2019-07-18 21:30  蓝田日暖玉生烟  阅读(194)  评论(0编辑  收藏  举报