bzoj 1659: [Usaco2006 Mar]Lights Out 关灯(IDA*)

1659: [Usaco2006 Mar]Lights Out 关灯

Time Limit: 5 Sec   Memory Limit: 64 MB
Submit: 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;
}

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页