护卫小队 题解
二、思路:
这是一道经典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;
}