【DFS】【结论】费解的开关

这篇博客探讨了一种名为'拉灯'的游戏,其中25盏灯排成5x5矩阵,每次操作可以改变一盏灯的状态并影响其相邻的灯。玩家的目标是在不超过6步的情况下使所有灯亮起。博主给出了问题的输入输出格式,并分享了使用DFS(深度优先搜索)算法解决该问题的思路,通过固定每一行并利用下一行的开关尝试关闭上一行的灯,最终检查是否所有灯都能点亮。

费解的开关

题目

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

解题思路

  • 其实这道题就是一道 结论+DFS,结论就是不断的固定每一行,然后就用下一行的开关来把上一行开的灯给关上,一直到最后一行,看是否有剩下的,如果有剩下的就说明这种方案不行,就继续搜下去,搜到没有并且是最优的即可.

程序如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int b[10][10],a[10][10],ans,n;
int cc(int winn)
{
	int s=winn;
	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])//计算这个点改变后的四个方向的变化
			{
				s++;//记步数
				b[i][j]=1-b[i][j];
				b[i+1][j]=1-b[i+1][j];
				b[i+1][j-1]=1-b[i+1][j-1];
				b[i+1][j+1]=1-b[i+1][j+1];
				b[i+2][j]=1-b[i+2][j];
			}
		}
	} 
	for(int i=1;i<=5;++i)
	{
		if(!b[5][i]) return 10;//看是否最后一行是否全部关完
	}
	return s;
}
void dfs(int win,int sum)
{
	if(win>5)//搜每一行
	{
		ans=min(ans,cc(sum));//取最优的
		return;
	}
	a[1][win]=1-a[1][win];//四个方向的改变
	a[1][win-1]=1-a[1][win-1];
	a[1][win+1]=1-a[1][win+1];
	a[2][win]=1-a[2][win];
	dfs(win+1,sum+1);//不改变
	a[1][win]=1-a[1][win];
	a[1][win-1]=1-a[1][win-1];
	a[1][win+1]=1-a[1][win+1];
	a[2][win]=1-a[2][win];
	dfs(win+1,sum);//改变
	return;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=5;++j)
		{
			for(int k=1;k<=5;++k)
			{
				scanf("%1d",&a[j][k]);//读入
			}
		}
		ans=10;//初始值
		dfs(1,0);//DFS
		if(ans<7) printf("%d\n",ans);
		else printf("-1\n"); 
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值