很有趣的一道dp题
我们先换个角度看这道题
我们可以把他看作,最多取出k,然后把一样的放一起,在放到一个地方去,使得答案最小
我们考虑dp
设(f[i][j][o][la])表示第(i)本书,取了(j)本,然后没有取出的书种类状态(o),最后一个没有取出的为(la)的答案
那么就有状态转换方程
当前这本不取出
(f[i][j][o][la]=min:{f[i-1][j][o|(1<<a[i])][a[i]]+[a[i]!=la]})
否则
(f[i][j][o][la]=min:{f[i-1][j-1][o][la]+((ospace and space((1<<a[i])) orspace is[i][a[i]])?0:1)})
其中(is[i][j])表示位置(i)处(j)为不为最后一个
#include<bits/stdc++.h>
#define N 511
#define K 111
#define M 9
using namespace std;
int n,k,a[N];
bool is[N][M];
int f[2][K][1<<M][M];
inline void work(int t){
scanf("%d%d",&n,&k);
if(!n&&!k)exit(0);
memset(is,0,sizeof(is));
int i,j,o,la;
for(i=1;i<=n;++i){
scanf("%d",&a[i]);
a[i]-=25;
}
for(i=1;i<=n;++i)
for(j=i+1;j<=n;++j)
is[i][a[j]]=1;
memset(f[0],63,sizeof(f[0]));
f[0][0][0][8]=0;
for(i=1;i<=n;++i){
memset(f[i&1],63,sizeof(f[i&1]));
for(j=0;j<=k;++j)
for(o=0;o<(1<<8);++o)
for(la=0;la<=8;++la)
if(la==8||o&(1<<la)){
f[i&1][j][o|(1<<a[i])][a[i]]=min(f[(i&1)^1][j][o][la]+(a[i]!=la),f[i&1][j][o|(1<<a[i])][a[i]]);
if(j>=1)f[i&1][j][o][la]=min(f[i&1][j][o][la],f[(i&1)^1][j-1][o][la]+(((o&(1<<a[i]))||is[i][a[i]])?0:1));
}
}
int ans(1e9);
for(j=0;j<=k;++j)
for(o=0;o<(1<<8);++o)
for(la=0;la<=8;++la)if(la==8||o&(1<<la))ans=min(ans,f[n&1][j][o][la]);
printf("Case %d: %d
",t,ans);
}
int main( ){
int i;
for(i=1;;++i)
work(i);
}