天天看点

HDU 3237 Help Bubu(DP)

题目链接:点击打开链接

思路:

比赛时查一点出, 需要加一个优化才能防止超时(恶心), 状态很容易想到: 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;
}