码迷,mamicode.com
首页 > 其他好文 > 详细

10.4 Help Bubu

时间:2019-10-04 23:20:33      阅读:293      评论:0      收藏:0      [点我收藏+]

标签:位置   相同   get   mem   mes   open   for   cstring   sizeof   

题意

Bubu的书架上有\(N\)本书。定义混乱值为连续相同高度书本的段数

你可以取出至多\(K\)本书并把它们插入到书架的任意个位置。请最小化最后书架的混乱度并输出

\(N\leq 500,K\leq 100\),书的高度在\(25\)\(32\)之间


解法

观察到书的高度只有\(8\)种取值,考虑进行状压

想象一个DP过程:在\(N\)本书中取出\(K\)本放在一边,在每本书取\(/\)不取都考虑完后,把取出的\(K\)本书插进书架中:具体的插入方法是,如果有与这本书高度相同的书,那么就插进去;否则在原有的基础上贡献\(1\)混乱度

我们可以设出状态\(f[i][j][k][S]\)代表前\(i\)个数,取出了\(j\)本书,书架中剩下的最后一本书的高度为\(k\),目前在书架中的书的种类\(S\)(状压后)

转移时,我们只需要讨论当前第\(i\)本书是取出来还是留在书架里

若取出来
\[ f[i][j][k][S]=min\{f[i-1][j-1][k][S]\} \]
若留在书架里
\[ f[i][j][h_i][S∪h_i]=min\{f[i-1][j][k][S]+[k\neq h_i]\} \]
那么最后统计答案时
\[ ans=\sum f[N][K][k][S]+btc(S \oplus s) \]
这里的\(\oplus\)运算指的是异或运算,\(btc\)指的是二进制位中一的个数

这也很好理解,因为按照上面我们思考的DP过程,我们只需要统计被取出来但书架中没有出现该高度的书的个数即可


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>

using namespace std;

int read();

int N, K, cs;

int a[510], btc[300];
int f[2][110][10][300];

inline void chkmin(int& x, int y) { x = x < y ? x : y; }

int main() {
    
//  freopen("book.in", "r", stdin);
//  freopen("book.out", "w", stdout);

    for (int i = 1; i < (1 << 8); ++i)  btc[i] = btc[i >> 1] + (i & 1);
    
    while (true) {
    
        N = read(), K = read(); 
        if (!N && !K)  break;       
        
        for (int i = 1; i <= N; ++i)  a[i] = read() - 24;
    
        memset(f[1], 0x3f, sizeof f[1]);
        f[1][0][a[1]][1 << (a[1] - 1)] = 1, f[1][1][0][0] = 0;
            
        for (int i = 2; i <= N; ++i) {
            memset(f[i & 1], 0x3f, sizeof f[i & 1]);
            for (int j = 0; j <= i && j <= K; ++j)
                for (int k = 0; k <= 8; ++k)
                    for (int S = 0; S < (1 << 8); ++S) {
                        if (j)  chkmin(f[i & 1][j][k][S], f[(i - 1) & 1][j - 1][k][S]);
                        chkmin(f[i & 1][j][a[i]][S | (1 << (a[i] - 1))], f[(i - 1) & 1][j][k][S] + (a[i] != k));
                    }
        }
    
        int s = 0;
        for (int i = 1; i <= N; ++i)  s |= (1 << (a[i] - 1));
    
        int ans = 0x3f3f3f3f;
        
        for (int i = 1; i <= 8; ++i)
            for (int j = 0; j <= K; ++j)
                for (int S = 0; S < (1 << 8); ++S)
                    ans = min(ans, f[N & 1][j][i][S] + btc[S ^ s]); 
    
        printf("Case %d: %d\n\n", ++cs, ans);
    }
    return 0;
}

int read() {
    int x = 0, c = getchar();
    while (!isdigit(c))  c = getchar();
    while (isdigit(c))   x = x * 10 + c - 48, c = getchar();
    return x;   
}

10.4 Help Bubu

标签:位置   相同   get   mem   mes   open   for   cstring   sizeof   

原文地址:https://www.cnblogs.com/VeniVidiVici/p/11623268.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!