Description
奶牛们喜欢在黑暗的环境里睡觉。当她们每晚回到牛棚准备睡觉时,牛棚里有L(3<=L<=50)盏灯仍然亮着。所有灯的开关按编号升序排成一列,最左边的那个开关控制1号灯(所谓控制,也就是如果1号灯现在亮着,那么按这个开关会使1号灯熄灭,否则这个操作会使1号灯被点亮)。由于奶牛们的蹄子过于粗大,没法方便地按开关,她们总是用一个特制的干草叉来进行对开关的操作。这个叉子设计了T(1<=T<=7)个叉尖,相邻叉尖的距离正好与相邻开关的距离相等。但是现在有些叉尖被折断了。比如说,T=4的一个干草叉,它的第3根叉尖被折断了,我们就用'1101'来描述它。
如果把这个叉子的最左端对准那一列开关的最左端,按下,那1号、2号和4号灯的状态会被改变(3号灯的状态不变,因为那个叉尖被折断了)。在进行这样的操作的时候,任何一个叉尖都必须有一个对应的开关,也就是说,叉子的边缘不能在那一列开关的范围外,即使边缘处的叉尖已经被折断。
现在,你已经知道了各个灯的状态,以及干草叉现在的情况,请你找出一个操作序列,使得在所有操作完成之后,仍然亮着的灯的数目最少。
第1行: 两个用空格隔开的整数:L 和 T
第2行: 一个长度为L的字符串,串中不含空格且元素均为'0'或'1'。第i个元素是'1'则表示第i盏灯亮着,是'0'的话就表示第i盏灯已经被关掉
第3行: 一个长度为T的字符串,只含'0'或'1'(同样不含空格)。如果第i个元素是'1',说明干草叉的第i根叉尖仍完好无损,否则说明第i根叉尖已经被折断
Output
第1行: 输出一个正整数K,即为了达到目的一共需要用叉子按多少次开关
10 4
1111111111
1101
Sample Output
5
Solutoin
由于叉子最多7个齿,而灯不超过50盏,所以可以使用状压DP。
f[i][j][k]表示前i盏灯,j盏亮着,k为后T-1盏的二进制状态。
从i到i+1时,可以选着叉或不叉。
t=k*2+a[i+1];
p=t^z;
t=p%(1<<(l-1));
f[i+1][j-h[k]+h[p]][t]=min(f[i+1][j-h[k]+h[p]][t],f[i][j][k]+1);
t=k*2+a[i+1];
t=t%(1<<(l-1));
f[i+1][j+a[i+1]][t]=min(f[i+1][j+a[i+1]][t],f[i][j][k]);
h[i]表示i二进制下1的个数
using namespace std;
int a[N],z=0;
int h[T];
int f[N][N][T];
int l,n,t,p;
int ans,s;
char c;
void pre()
{
for (int i=0;i<T;++i)
{
int j=i;
while (j!=0)
{
h[i]+=j%2;
j=j/2;
}
}
}
void init()
{
scanf("%d%d\n",&n,&l);
for (int i=1;i<=n;++i)
{
c=getchar();
if (c=='1') a[i]=1;
else a[i]=0;
}
scanf("\n");
for (int i=l;i>=1;--i)
{
c=getchar();
if (c=='1') t=1;
else t=0;
z+=t*(1<<(i-1));
}
}
int main()
{
freopen("xlite.in","r",stdin);
freopen("xlite.out","w",stdout);
pre();
init();
for (int i=0;i<=n;++i)
for (int j=0;j<=n;++j)
for (int k=0;k<=(1<<l)-1;++k)
f[i][j][k]=INF/2;
t=0; p=0;
for (int i=1;i<=l-1;++i)
{
t+=a[i];
p=p*2+a[i];
}
f[l-1][t][p]=0;
for (int i=0;i<=n;++i)
for (int j=0;j<=n;++j)
for (int k=0;k<=(1<<(l-1))-1;++k)
if (f[i][j][k]!=INF/2)
{
t=k*2+a[i+1];
p=t^z;
t=p%(1<<(l-1));
//printf("p=%d t=%d\n",p,t);
//printf("%d %d %d %d %d\n",i,j-h[k]+h[p],t);
f[i+1][j-h[k]+h[p]][t]=min(f[i+1][j-h[k]+h[p]][t],f[i][j][k]+1);
t=k*2+a[i+1];
t=t%(1<<(l-1));
f[i+1][j+a[i+1]][t]=min(f[i+1][j+a[i+1]][t],f[i][j][k]);
}
s=n;
ans=INF/2;
for (int i=0;i<=n;++i)
for (int j=0;j<=(1<<(l-1))-1;++j)
if (f[n][i][j]!=INF)
if (i<=s && f[n][i][j]<ans)
{
s=i;
ans=f[n][i][j];
}
else if (i>s) break;
printf("%d\n",ans);
return 0;
}