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
#include
#include
#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);
}