2813 - 帮助Bubu

通过次数

0

提交次数

0

时间限制 : 2 秒 内存限制 : 128 MB

Bubu的书架乱成一团了!帮他一下吧!

他的书架上一共有n本书。我们定义混乱值是连续相同高度书本的段数。例如,如果书的高度是30,30,31,31,32,那么混乱值为330,32,32,31的混乱度也是3,31,32,31,32,31的混乱度是5-这实在是太乱了。

Bubu想尽可能的减少混乱度,但他有点累了,所以他决定最多取出k本书,再随意将他们放到书架上。你能帮助他吗?

题目输入

Input:

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

题目输出

Output:

对于每一组数据,输出Case标号和最终最小的混乱度。在每组数据后打印一个空行。

输入/输出样例

输入格式

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

输出格式

Case 1: 2

Case 2: 3

C++解答

#include<cstdio>
#include<cstring>
using namespace std;
#define min(a,b) ((a)<(b)?(a):(b))
#define inf ((1<<30)-1)
int dp[2][105][1<<8][10];
int tall[105],num[1<<8];
int main()
{
    int n,m,begin;
    //预处理
    memset(num,0,sizeof(num));
    for(int i=0; i<(1<<8); ++i)
        for(int j=0; j<8; ++j)
            if(i&(1<<j)) num[i]++;
    for(int cas=1;~scanf("%d%d",&n,&m);++cas)
    {
        if(n+m==0) break;
        begin=0;//初始高度状态
        for(int i=1; i<=n; ++i)
        {
            scanf("%d",&tall[i]);
            tall[i]-=25;
            begin=begin|(1<<tall[i]);
        }
        for(int i=0; i<=m; ++i)//取走的次数
            for(int j=0; j<(1<<8); ++j)//高度状态
                for(int k=0; k<=8; ++k)//最后的书的高度
                    dp[0][i][j][k]=inf;
        dp[0][0][0][8]=0;//起始点
        for(int i=1; i<=n; ++i)
        {
            for(int j=0; j<=m; ++j)
                for(int k=0; k<(1<<8); ++k)
                    for(int s=0; s<=8; ++s)
                        dp[i&1][j][k][s]=inf;
            for(int j=0; j<i&&j<=m; ++j)
                for(int k=0; k<(1<<8); ++k)
                    for(int s=0; s<=8; ++s)
                        if(dp[(i-1)&1][j][k][s]!=inf)
                        {
                            //取走第i位
                            if(j<m)        dp[i&1][j+1][k][s]=min(dp[i&1][j+1][k][s],dp[(i-1)&1][j][k][s]);
                            //不取走第i位且高度与前一个相同
                            if(s==tall[i]) dp[i&1][j][k][s]=min(dp[i&1][j][k][s],dp[(i-1)&1][j][k][s]);
                            //不取走第i位且高度与前一个不同
                            else           dp[i&1][j][k|(1<<tall[i])][tall[i]]=min(dp[i&1][j][k|(1<<tall[i])][tall[i]],dp[(i-1)&1][j][k][s]+1);
                        }
        }
        int ans=inf;
        for(int i=0; i<=m; ++i)
            for(int j=0; j<(1<<8); ++j)
                for(int k=0; k<8; ++k)
                    if(dp[n&1][i][j][k]!=inf)
                    {
                        int temp=j^begin;//不在此状态且拿出的书的高度
                        if(ans>dp[n&1][i][j][k]+num[temp])
                            ans=dp[n&1][i][j][k]+num[temp];
                    }
        printf("Case %d: %d\n\n",cas,ans);
    }
    return 0;
}