您的位置:首页 > 其它

uva 10318(dfs+状态压缩)

2015-04-21 23:42 447 查看
题意:有一个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
[2], n, change
, r, c, tar, now
, ans
, 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
[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dfs 暴力 uva