题目链接:点击打开链接
思路:
比赛时查一点出, 需要加一个优化才能防止超时(恶心), 状态很容易想到: d[i][j][s][k]表示前i本书拿了j本没拿的书的集合是s没拿的书的最后一本是k的最优解。
为什么状态压缩的是目前桌子上的书的集合呢? 因为我们要防止一种情况:那就是如果对于高度为H的一种书, 我们都拿走了, 那么还要放回桌子上, 最优解要+1, 这样表示之后, 我们只要判断一下有几种书桌子上没有就行了。
细节参见代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const double eps = 1e-6;
const double PI = acos(-1);
const int mod = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
// & 0x7FFFFFFF
const int seed = 131;
const ll INF64 = ll(1e18);
int T,n,K,a[111],d[2][111][(1<<8)][10], kase = 0;
int tot, state,one[1<<8];
inline void init(int u) {
for(int j = 0; j <= K; j++) {
for(int s = 0; s < (1<<(tot+1)); s++) {
for(int k = 0; k <= tot+1; k++) {
d[u][j][s][k] = INF;
}
}
}
}
void Initial() {
for (int i = 0; i < (1<<8); ++i) {
for (int j = 0; j < 8; ++j)
if (i & (1<<j)) one[i]++;
}
}
int main() {
Initial();
while(~scanf("%d%d", &n, &K)) {
if(n == 0 && K == 0) break;
tot = 0;
state = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i] -= 25;
tot = max(tot, a[i]);
state |= 1<<a[i];
}
int u = 0;
init(u);
d[u][0][0][tot+1] = 0;
for(int i = 0; i < n; i++) {
int id = a[i+1];
u ^= 1;
init(u);
for(int j = 0; j <= K; j++) {
for(int s = 0; s < (1<<(tot+1)); s++) {
for(int k = 0; k <= tot+1; k++) {
int& ans = d[u^1][j][s][k];
if(ans == INF) continue;
if(j < K) d[u][j+1][s][k] = min(d[u][j+1][s][k], ans);
if(k != id) d[u][j][s|(1<<id)][id] = min(d[u][j][s|(1<<id)][id], ans+1);
else d[u][j][s][id] = min(d[u][j][s][id], ans);
}
}
}
}
int ans = INF;
for(int j = 0; j <= K; j++) {
for(int s = 0; s < (1<<(tot+1)); s++) {
for(int k = 0; k < tot+1; k++) {
int cur = 0;
if(d[u][j][s][k] == INF) continue;
int st = state ^ s;
ans = min(ans, d[u][j][s][k] + one[st]);
}
}
}
printf("Case %d: %d\n\n", ++kase, ans);
}
return 0;
}