CH0201 费解的开关

描述

你玩过“拉灯”游戏吗?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

题意:如题目所述

思路:

       首先先明确两个问题:

1.对于一个开关,我们按下的次数以及按它周围的开关对它所造成的影响,其实就两种情况,改变状态或者不变。显然偶数次就是不变。所以对于每个开关,我们最多按下一次。

2.如果我们确定了第一行中有那几个开关按下,那第一行的状态也就确定了。对于第一行还关着的灯,我们只能通过它的下一行的同一列的开关来改变。这样当我们把第一行的灯全部变亮的时候,第二行的状态也就确定了。这样递推把前四行的灯全部变亮。对于最后一行,如果还有灯关着,那我们就不可能把所有灯打开。

 

第一行灯只有5个,那我可以用二进制枚举第一行的所有情况。

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define forn(i,a,b) for(int i=a;i<=b;i++)

int n,mp[7][7];
char m[7][7];
int dx[] = {1,0,-1,0,0};
int  dy[] = { 0,1,0,-1,0 };

void solve(int x,int y) {
	forn(i, 0, 4){
		if (x + dx[i] >= 0 && x + dx[i] <= 4 && y + dy[i] >= 0 && dy[i] + y <= 4)
			mp[x + dx[i]][y + dy[i]] ^= 1;
	}
	
}                                                                                                                                                                                                                                                                                                                                      
int main() {
	scanf("%d",&n);
	while (n--) {
		for (int i = 0; i < 5; i++)scanf("%s",m[i]);

		int ans = 10;
		forn(k, 0, 31) {
			int cnt = 0;
			forn(i, 0, 4)forn(j, 0, 4)mp[i][j] = m[i][j] - '0';
			forn(i, 0, 4)if (k&(1 << i)) { cnt++; solve(0, i); }

			forn(i, 0, 3)forn(j, 0, 4) {
				if (!mp[i][j]) { cnt++; solve(i + 1, j); }
			}

			int ju = 1;
			forn(i, 0, 4)if (mp[4][i] == 0) { ju = 0; break; }

			if (ju&&cnt<=6&&ans>cnt) {
				ans = cnt;
			}
		}

		printf("%d\n",ans==10?-1:ans);
		
	}
	return 0;
}

代码如下:

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值