题目描述
你玩过“拉灯”游戏吗?25盏灯排成一个5x5的方形。每一个灯都有一个开关,游戏者可以改变它的状态。每一步,游戏者可以改变某一个灯的状态。游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态。
我们用数字“1”表示一盏开着的灯,用数字“0”表示关着的灯。下面这种状态
10111
01101
10111
10000
11011
在改变了最左上角的灯的状态后将变成:
01111
11101
10111
10000
11011
再改变它正中间的灯后状态将变成:
01111
11001
11001
10100
11011
给定一些游戏的初始状态,编写程序判断游戏者是否可能在6步以内使所有的灯都变亮。
输入格式
第一行输入正整数n,代表数据中共有n个待解决的游戏初始状态。
以下若干行数据分为n组,每组数据有5行,每行5个字符。每组数据描述了一个游戏的初始状态。各组数据间用一个空行分隔。
输出格式
一共输出n行数据,每行有一个小于等于6的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。
对于某一个游戏初始状态,若6步以内无法使所有灯变亮,则输出“-1”。
数据范围
0<n≤500
样例
输入样例:
3
00111
01011
10001
11010
11100
11101
11101
11110
11111
11111
01111
11111
11111
11111
11111
输出样例:
3
2
-1
(暴力BFS)
时间复杂度 $O(2^25)$ 大概 3*10^7勉强能过 QWQ
看完题,我们就发现这一题的状态是有限的,计算一下时间复杂度,勉强可以不会超时,可以搞一下;
总体这个算法分为2步: 1.做一个预处理,将所有6步的状态以及步数存储起来; 2.对输入的状态进行哈希得到步数;
所有数据都是0和1,所以进一步来说,我们可以进行状态压缩,用一个整形对一个状态进行存储表示.
参考文献
C++ 代码
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e7+10;
const ll mod = 1000000007;
unordered_map<int,int>vis;
int build(int x,int p)
{
x ^= ( 1<< p);
if(p % 5) x ^= (1 << (p - 1));
if(p >= 5) x ^= (1 << (p - 5));
if(p < 20) x ^= (1 << (p + 5));
if((p % 5) < 4) x ^= (1 << (p + 1));
return x;
}
void bfs()
{
queue<int> que;
int now = (1 << 25) - 1;
vis[now] = 1;
que.push(now);
while(!que.empty())
{
int top = que.front();
que.pop();
if(vis[top] == 7) break;
for(int i = 0;i < 25;i++)
{
now = build(top,i);
if(!vis.count(now))
{
vis[now] = vis[top] + 1;
que.push(now);
}
}
}
}
int main()
{
bfs();
int T;
scanf("%d",&T);
while(T--)
{
int sum = 0;
for(int i = 0;i < 25;i++)
{
char t;
cin >> t;
sum += ((t - '0') << i);
}
printf("%d\n",vis[sum] - 1);
}
return 0;
}
我这种菜鸡只会后来再判断
您好, 请问您的这个解法和up的解法的主要区别在于哪里? 看了看似乎没看出
后来再判断
是啥意思. 谢谢!这变化太巧了
x ^= ( 1<< p); 这是啥意思呀
变换自己的状态
时间复杂度不太明白
$\mathcal{O}(2^{25})$,他打错了
解释下这两行代码:
1.状态合法,前面最终状态初始化为1了,得-1
2.因为>7步的没有赋值,不合法,输出 −1。
%%%找了一圈 终于找到bfs的
必须得压缩成整数,用一个字符串表示状态会被卡常....
%%%%%%%%%%%%%%%%%%%
如何hash?