[状压DP]帮助Bubu

题目描述

Bubu的书架乱成一团了!帮他一下吧!
他的书架上一共有n本书。我们定义混乱值是连续相同高度书本的段数。例如,如果书的高度是30,30,31,31,32,那么混乱值为3,30,32,32,31的混乱度也是3,但31,32,31,32,31的混乱度是5-这实在是太乱了。
Bubu想尽可能的减少混乱度,但他有点累了,所以他决定最多取出k本书,再随意将他们放到书架上。你能帮助他吗?

Input

最多会有20组测试数据。每组测试数据开头为两个整数n,k(1<=k<=n<=100),表示总共有n本书,最多可以进行k次搬书操作。接下来一行有n个整数,表示每本书的高度,从左到右。每本书的高度是25到32间的整数。最后一组数据后有一行n=k=0。

Output

对于每一组数据,输出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

分析

容易想到转移fi,j,k表前i本移动j本且最后一次移动的书编号为k的方程
然后我们发现如果单纯向前或后转移会有纰漏,而且书的种类只有8种,所以考虑加一维l二进制表示某种书的移动状况
容易分成三种转移:
1、不动(如果没有被作为被移动位置的书就要+1)
2、向后移到最后一位,自己成为一个独立的段(如果没有被移动过也+1)
3、往前面有相同的书本移(如果有,显然不会增加混乱度,因为已经加过了)

#include <iostream>
#include <cstdio>
#include <memory.h>
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
int n,k,ds,cnt;
int i,j,k1,l,gd;
int f[2][101][9][1<<8];
int a[101],b[101],s[101];
bool fx[101],hq[101];
int ans;
int main()
{
    do
    {
        scanf("%d%d",&n,&k);
        cnt++;
        if (n==k&&n==0) break;
        ds=0;
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(s,0,sizeof(s));
        rep(i,1,n)
        {
            scanf("%d",&a[i]);
            a[i]-=24;
            if (a[i]!=a[i-1])
            b[++ds]=a[i];
            s[ds]++;
        }
        memset(f[0],10,sizeof(f[0]));
        f[0][0][0][0]=0;
        memset(fx,0,sizeof(fx));
        memset(hq,0,sizeof(hq));
        for (i=ds;i>=1;i--)
        {
            if (fx[b[i]]) hq[i]=1;
            fx[b[i]]=1;
        }
        gd=0;
        rep(i,1,ds)
        {
            gd=gd^1;
            memset(f[gd],10,sizeof(f[gd]));
            rep(j,0,k)
            rep(k1,0,8)
            rep(l,0,(1<<8)-1)
            {
                if (f[gd^1][j][k1][l]>n) continue;
                f[gd][j][b[i]][l|(1<<(b[i]-1))]
                =min(f[gd][j][b[i]][l|(1<<(b[i]-1))],
                f[gd^1][j][k1][l]+(b[i]!=k1));
                if (j+s[i]>k) continue;
                f[gd][j+s[i]][k1][l|(1<<(b[i]-1))]
                =min(f[gd][j+s[i]][k1][l|(1<<(b[i]-1))],
                f[gd^1][j][k1][l]+!(l&(1<<(b[i]-1))));
                if (hq[i])
                f[gd][j+s[i]][k1][l]
                =min(f[gd][j+s[i]][k1][l],
                f[gd^1][j][k1][l]);
            }
        }
        ans=n;
        rep(j,0,k)
        rep(k1,0,8)
        rep(l,0,(1<<8)-1)
        ans=min(ans,f[gd][j][k1][l]);
        printf("Case %d: %d\n\n",cnt,ans);
    }
    while (1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值