费解的开关
时间限制: 1 Sec 内存限制: 128 MB
提交: 105 解决: 39
[提交] [状态] [讨论版] [命题人:admin]
题目描述
你玩过“拉灯”游戏吗?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个字符。每组数据描述了一个游戏的初始状态。各组数据间用一个空行分隔。
对于30%的数据,n<=5;
对于100%的数据,n<=500。
输出
输出数据一共有n行,每行有一个小于等于6的整数,它表示对于输入数据中对应的游戏状态最少需要几步才能使所有灯变亮。
对于某一个游戏初始状态,若6步以内无法使所有灯变亮,请输出“-1”。
样例输入
3
00111
01011
10001
11010
11100
11101
11101
11110
11111
11111
01111
11111
11111
11111
11111
样例输出
3
2
-1
题意
给出n个5×5的开关,按下一个开关会影响周围4个灯和自己(开变成关,关变成开)。求最少需要按多少次开关才能使得全部灯变亮?(6次以上则视为无法点亮)。
题解
首先我们要枚举第一行灯开关的所有情况,那么如果要改变第一行的灯的状态,那么就只能更改第二行的位于该灯下面的那个开关来改变。
如果我们固定了第一行,那么为了将全部都变成绿色,就必须利用第二行。例如,(1,1)(1,1)是红色,为了让它变成绿色,就必须更改(2,1)(2,1)。为了让(1,4)(1,4)变成绿色,就必须更改(2,4)(2,4)。
更改后图形如下:
那么我们再固定第二行,利用第三行来更改它(就像用第一行来更改第二行一样),就变成了
同理,更改第三行
再更改第四行
这是我们发现,最后还有一个灯是关着的,所以,这说明第一行的灯如果是这样的情况就无法成立
那么就继续枚举第一行的点击方式,再继续按照刚才的方法,判断能否点完即可。
#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#define Inf 0x3f3f3f
#define ll long long
using namespace std;
int t;
int ans;
int a[10][10];
int b[10][10];
int check(int cnt)//判断第一行的条件是否成立
{
int sum=cnt;
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
b[i][j]=a[i][j];
for(int i=1;i<=4;i++)
{
for(int j=1;j<=5;j++)
{
if(!b[i][j])
{
sum++;
b[i][j]=!b[i][j];
b[i+1][j]=!b[i+1][j];
b[i+1][j-1]=!b[i+1][j-1];
b[i+1][j+1]=!b[i+1][j+1];
b[i+2][j]=!b[i+2][j];
}
}
}
for(int i=1;i<=5;i++)
if(!b[5][i])return Inf;
return sum;
}
int dfs(int cnt,int k)
{
if(cnt>5)
{
ans=min(ans,check(k));
return 0;
}
a[1][cnt]=!a[1][cnt];
a[1][cnt-1]=!a[1][cnt-1];
a[1][cnt+1]=!a[1][cnt+1];
a[2][cnt]=!a[2][cnt];
dfs(cnt+1,k+1);//按下这个开关
a[1][cnt]=!a[1][cnt];
a[1][cnt-1]=!a[1][cnt-1];
a[1][cnt+1]=!a[1][cnt+1];
a[2][cnt]=!a[2][cnt];
dfs(cnt+1,k);//不按下这个开关
}
int main()
{
scanf("%d",&t);
while(t--)
{
for(int i=1;i<=5;i++)
for(int j=1;j<=5;j++)
scanf("%1d",&a[i][j]);
ans=Inf;
dfs(1,0);
if(ans<7)printf("%d\n",ans);
else printf("-1\n");
}
return 0;
}