zoukankan      html  css  js  c++  java
  • 10.4 Help Bubu

    题意

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

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

    (Nleq 500,Kleq 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 eq 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
    
    ", ++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;	
    }
    
  • 相关阅读:
    Http协议的断点续传下载器,使用观察者模式监视下载进度,使用xml保存下载进度。
    C++ 复制到粘贴板
    编译防火墙——C++的Pimpl惯用法解析
    字符串输出
    windows路径操作API函数
    Boost解析xml——xml写入
    智能指针shared_ptr
    Boost 解析xml——插入Item
    ListCtrl添加右键菜单(在对话框类中)
    抓包工具Charles的使用说明
  • 原文地址:https://www.cnblogs.com/VeniVidiVici/p/11623268.html
Copyright © 2011-2022 走看看