1659: [Usaco2006 Mar]Lights Out 关灯
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 298 Solved: 73
[ Submit][ Status][ Discuss]
Description
奶牛们喜欢在黑暗中睡觉。每天晚上,他们的牲口棚有L(3<=L<=50)盏灯,他们想让亮着的灯尽可能的少。他们知道按钮开关的位置,但喜闻乐见的是他们并没有手指。你得到了一个长度为T(1<=T<=7)的插槽用以帮助奶牛们改变灯的状态。
Input
第一行,两个整数L和T。第二行给出一个长度为L的01串表示初始灯的状态,0表示灯是灭的,1表示灯是亮的。第三行给出一个长度为T的01串,表示你获得的插槽。
Output
第一行输出一个整数K,表示在满足亮着的灯最少的情况下,你要用插槽操作的次数。第二行到第K+1行,每行一个整数表示你的插槽使用的位置。
"K最小的解,并且满足解的字典序最大(即按钮开关的位置尽可能靠后)"
Sample Input
10 4
1111111111
1101
Sample Output
5
1
3
4
6
7
因为最后可以留亮灯,所以枚举就不行了
很好想到IDA*,阈值H就是最小亮灯数,从小到大暴力H即可
lit:估价函数,当前有多少个灯到最后一定是亮着的(比如你按顺序按槽,当前按完第一个,准备考虑按不按下一个,那么第一个灯的状态就不会再改变了,如果它是亮着的,lit++),lit>H就剪枝
#include<stdio.h>
#include<string.h>
int bet, ok, H, n, m, a[52], b[10], temp[55], ans[55];
void Sech(int id, int now, int lit)
{
int i, sum;
if(lit>H || now>bet)
return;
if(id==n-m+2)
{
sum = lit;
for(i=id;i<=n;i++)
{
if(a[i])
sum++;
}
if(sum>H)
return;
if(now<=bet) //要取字典序最大的,所以是<=
{
ok = 1;
bet = now;
memcpy(ans, temp, sizeof(ans));
}
return;
}
temp[id] = 1;
for(i=1;i<=m;i++)
a[id+i-1] ^= b[i];
Sech(id+1, now+1, lit+a[id]);
for(i=1;i<=m;i++)
a[id+i-1] ^= b[i];
temp[id] = 0;
Sech(id+1, now, lit+a[id]);
}
int main(void)
{
int i;
scanf("%d%d", &n, &m);
for(i=1;i<=n;i++)
scanf("%1d", &a[i]);
for(i=1;i<=m;i++)
scanf("%1d", &b[i]);
bet = n+1;
for(H=0;H<=n;H++)
{
ok = 0;
Sech(1, 0, 0);
if(ok)
break;
}
printf("%d\n", bet);
for(i=1;i<=n;i++)
{
if(ans[i])
printf("%d\n", i);
}
return 0;
}