难啊!
分析题目,发现书高范围挺小的,估摸着是个状态压缩。
然后就卡住了,再然后无比熟练的找到了题解
先思考状态吧。首先前 i 个,选 j 个肯定是要有的。
决策肯定是选和不选。
不选的时候,messval的值肯定跟上一个结尾的高度有关,所以状态里肯定有结尾的高度。
很明显,肯定要记录 拿走或者剩余哪些高度 以及 所有的高度。
于是终于思考出状态 :
int f[2][MAXN][MAXH][10];//前i个, 选j个, 书架上剩余书目集合, 最后一本书的高度
然后就可以码了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e2 + 5;
const int MAXH = (1 << 8) + 2;
int f[2][MAXN][MAXH][10];//前i个, 选j个, 书架上剩余书目集合, 最后一本书的高度
int N, K;
int main()
{
int T = 0;
while(cin>>N>>K, (N + K))
{
int d = 0, all = 0;
memset(f[d], 0x3f, sizeof(f[d]));
for(int i = 0; i < N; i++){
int h; scanf("%d", &h);
h -= 25;
d ^= 1; memset(f[d], 0x3f, sizeof(f[d]));
f[d][i][(1 << h)][h] = 1;
for(int j = 0; j <= min(i, K); j++)
for(int s = all; s; s = (s - 1) & all)
for(int k = 0; k < 8; k++){
if(f[d ^ 1][j][s][k] == INF) continue;
if(h == k) f[d][j][s][h] = min(f[d][j][s][h], f[d ^ 1][j][s][k]);//不拿
else {
f[d][j][s | (1 << h)][h] = min(f[d][j][s | (1 << h)][h], f[d ^ 1][j][s][k] + 1);
f[d][j + 1][s][k] = min(f[d][j + 1][s][k], f[d ^ 1][j][s][k]);//拿
}
}
all |= (1 << h);
}
int ans = INF;
for(int j = 0; j <= K; j++)
for(int s = all; s; s = (s - 1) & all)
for(int k = 0; k < 8; k++){
if(f[d][j][s][k] == INF) continue;
int cnt = 0;
for(int tmp = s ^ all; tmp; tmp >>= 1)
if(tmp & 1) ++cnt;
ans = min(ans, f[d][j][s][k] + cnt);
}
printf("Case %d: %d
", ++T, ans);
}
return 0;
}