状态压缩。四维。当前到达第几本书、已经选了几本书、之前没选的书所构成的状态、前一本书。一开始没思路。看了下别人的题解。之前一直让我困惑的就是第三维解决的问题,只要记录没选的书的状态即可。最后加上选走且剩下的书中没有的书种类数几位最终复杂度。据别人题解说要用滚动数组。也没有心情自己去试了,直接用吧。代码注释中有一需要注意的部分。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
using namespace std;
typedef long long LL;
#define INF 1000000007
#define N 1000
int n, m;
int a[105];
int dp[2][103][1 << 8][8];
void init(int x){
for(int i = 0; i <= n; i++){
for(int j = 0; j < (1 << 8); j++){
for(int k = 0; k < 8; k++){
dp[x][i][j][k] = INF;
}
}
}
}
int main(){
int num = 0;
while(scanf("%d%d", &n, &m), n || m){
int tot = 0;
for(int i = 0; i < n; i++){
scanf("%d", &a[i]);
a[i] -= 25;
tot |= 1 << a[i];
}
int f = 0;
init(f);
for(int i = 0; i < n; i++){
f = 1 - f;
init(f);
if(i <= m)dp[f][i][(1 << a[i])][a[i]] = 1;
//这样赋值无法记录所有书都被选走的情况,但是不影响结果,因为最后还要放回来。
for(int j = 0; j <= min(i, m); j++){
for(int k = 0; k < (1 << 8); k++){
if((k | tot) > tot)continue;
for(int l = 0; l < 8; l++){
if(dp[1 - f][j][k][l] == INF) continue;
if(l == a[i]){
dp[f][j][k][l] = min(dp[f][j][k][l], dp[1 - f][j][k][l]);
}
else {
dp[f][j][k | (1 << a[i])][a[i]] = min(dp[f][j][k | (1 << a[i])][a[i]], dp[1 - f][j][k][l] + 1);
dp[f][j + 1][k][l] = min(dp[f][j + 1][k][l], dp[1 - f][j][k][l]);
}
}
}
}
}
int ans = INF;
for(int i = 0; i <= m; i++){
for(int j = 0; j < (1 << 8); j++){
for(int k = 0; k < 8; k++){
if(dp[f][i][j][k] == INF)continue;
int s = 0;
for(int l = (tot ^ j); l > 0;){
if(l & 1) s ++;
l >>= 1;
}
if(s + dp[f][i][j][k] < ans)ans = s + dp[f][i][j][k];
}
}
}
printf("Case %d: %d\n\n", ++num, ans);
}
return 0;
}