uva12235 - Help Bubu 四维状态压缩DP

Bubu's bookshelf is in a mess! Help him!

There are n books on his bookshelf. We define the mess value to be the number of segments ofconsecutive equal-height books. For example, if the book heights are 30, 30, 31, 31, 32, the mess value is 3, that of 30, 32, 32, 31 is also 3, but the mess value of 31, 32, 31, 32, 31 is 5 -- it's indeed in a mess!

Bubu wants to reduce the mess value as much as possible, but he's a little bit tired, so he decided to take out at mostk books, then put them back somewhere in the shelf. Could you help him?

Input 

There will be at most 20 test cases. Each case begins with two positive integersn andk (1$ \le$k$ \le$n$ \le$100), the total number of books, and the maximum number of books to take out. The next line containsn integers, the heights of each book, from left to right. Each height is an integer between 25 and 32, inclusive. The last test case is followed byn = k = 0, which should not be processed.

Output 

For each test case, print the case number and the minimal final mess value. Print a blank line after the output of each test case.

Sample Input 

5 2 
25 25 32 32 25 
5 1 
25 26 25 26 25 
0 0

Sample Output 

Case 1: 2 

Case 2: 3

  看了别人的。。这个题能做出来的人真是大神。。

  N本书,吧相邻高度相同的看成一个片段,混乱程度为片段数。可以取走K本书,再插入回去。输出整理后混乱程度的最小值。

  先算出取走n本书的各种剩余状态的最小混乱值,插入时只要在剩余的书里没有要插入的书的这个高度,混乱度肯定就要加1。

  问题是怎么算取走n本书的各种剩余状态的最小混乱值。

  设dp[i][j][s][k]为前i本书,取走j本,剩余的书的状态为s,剩余的书的最后一本高度为k的最小混乱值。

  设第i本书高度为t,dp[i][i-1][1<<t][t]=1,这个是跟i之前的书状态没有关系的,只由第i本书决定。剩下的状态就跟i之前的有关系了。

  若dp[i-1][j][s][k]存在:

  如果 t=k, dp[i][j][s][k]=min(dp[i][j][s][k],dp[i-1][j][s][k])

  否则 不取走第i本书 dp[i][j][s|(1<<t)][t]=min(dp[i][j][s|(1<<t)][t],dp[i-1][j][s][k]+1)。

          取走第i本书 dp[i][j+1][s][k]=min(dp[i][j+1][s][k],dp[i-1][j][s][k])

  最后只要找dp[N][j][s][k]存在的情况加上放回增加的混乱度的最小值就行了。

  用滚动数组做省空间。

#include<cstring>
#include<cstdio>
#include<iostream>
#include<climits>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#define INF 0x3f3f3f3f
#define MAXN 110
#define MAXM 8
using namespace std;
int N,K;
int dp[2][MAXN][1<<MAXM][MAXM];
int main(){
    freopen("in.txt","r",stdin);
    int cas=0;
    while(scanf("%d%d",&N,&K),N||K){
        int pre,now=0,t,all=0;
        memset(dp[now],INF,sizeof(dp[now]));
        for(int i=0;i<N;i++){
            scanf("%d",&t);
            t-=25;
            pre=now;
            now=!now;
            memset(dp[now],INF,sizeof(dp[now]));
            dp[now][i][1<<t][t]=1;
            for(int j=0;j<=min(i,K);j++)
                for(int s=all;s;s=(s-1)&all)
                    for(int k=0;(1<<k)<=s;k++) if(dp[pre][j][s][k]!=INF){
                        if(t==k) dp[now][j][s][t]=min(dp[now][j][s][t],dp[pre][j][s][k]);
                        else{
                            dp[now][j][s|(1<<t)][t]=min(dp[now][j][s|(1<<t)][t],dp[pre][j][s][k]+1);
                            dp[now][j+1][s][k]=min(dp[now][j+1][s][k],dp[pre][j][s][k]);
                        }
                    }
            all|=(1<<t);
        }
        int ans=INF;
        for(int i=0;i<=K;i++)
            for(int s=all;s;s=(s-1)&all)
                for(int k=0;(1<<k)<=s;k++) if(dp[now][i][s][k]!=INF){
                    int cnt=0;
                    for(int s0=s^all;s0;s0>>=1) if(s0&1) cnt++;
                    ans=min(ans,cnt+dp[now][i][s][k]);
                }
        printf("Case %d: %d\n\n",++cas,ans);
    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值