题意:有一个r*c的密码锁,现在给出了解密方式,是一个3*3的矩阵,‘*’表示灯亮,'.'表示灯灭,然后对于每个密码锁,触动一个按键,相当于把这个按键对应到3*3矩阵中间的按键处,然后对应'*'的位置的灯都会亮,如果本来是亮的就会灭掉,问最快按哪些按钮可以使密码锁上每个按键的灯都亮。

题解:可以推出,按键顺序不同不影响按了这些键造成的结果,然后因为密码锁最多5*5,可以考虑用dfs暴力,然后因为有最多25个格子,那么可以用一个状态S表示当前亮了哪些灯,然后如果S == (1 << (r * c)) - 1说明灯全亮,然后还需要一个数组change[i],表示第i个按钮按到会造成哪些灯发生改变(也用二进制表示),这时候如果按了灯i,S ->  S ^ change[i],另外有个剪枝,如果已经枚举到k排的按钮了,这时候k - 2排还有灯没亮就直接return了,可以省很多时间。

#include <stdio.h>
#include <string.h>
const int N = 30;
const int INF = 0x3f3f3f3f;
int flag[N][2], n, change[N], r, c, tar, now[N], ans[N], res;
char g[3][3];

void solve() {
	int m = r * c;
	for (int i = 0; i < m; i++) {
		int x = i / c;
		int y = i % c;
		change[i] = 0;
		for (int j = 0; j < n; j++) {
			int xx = x + flag[j][0];
			int yy = y + flag[j][1];
			if (xx < 0 || yy < 0 || xx >= r || yy >= c)
				continue;
			int temp = xx * c + yy;
			change[i] |= (1 << temp);
		}
	}
}

void dfs(int S, int len, int cur) {
	if (S == tar && len < res) {
		res = len;
		int m = r * c;
		for (int i = 0; i < m; i++)			
			ans[i] = now[i];
		return;
	}
	if ((cur / c) >= 2) {
		int k = (cur / c) - 2;
		for (int i = k * c; i < k * c + c; i++)
			if (!(S & (1 << i)))
				return;
	}
	if (cur >= (r * c))
		return;
	now[cur] = 1;
	dfs(S ^ change[cur], len + 1, cur + 1);
	now[cur] = 0;
	dfs(S, len, cur + 1);
}

int main() {
	int cas = 1;
	while (scanf("%d%d", &r, &c) == 2 && r + c) {
		memset(now, 0, sizeof(now));
		for (int i = 0; i < 3; i++)
			scanf("%s", g[i]);
		n = 0;
		for (int i = 0; i < 3; i++)
			for (int j = 0; j < 3; j++)
				if (g[i][j] == '*') {
					flag[n][0] = i - 1;
					flag[n++][1] = j - 1;
				}
		solve();
		res = INF;
		tar = (1 << (r * c)) - 1;
		dfs(0, 0, 0);
		printf("Case #%d\n", cas++);
		if (res != INF) {
			int a = 0, m = r * c;
			for (int i = 0; i < m; i++) {
				if (ans[i] && a)
					printf(" %d", i + 1);
				if (ans[i] && !a) {
					printf("%d", i + 1);
					a = 1;
				}
			}
			printf("\n");
		}
		else
			printf("Impossible.\n");
	}
	return 0;
}