费解的开关

思路:

1.每个开关只用开一次,开偶数次没有用
2.顺序不影响结果
3.第一层为暗,要变亮它的下一层对应开关必须按,
即为每一层开关的状态由上一层唯一确定。
4.需要的总次数:固定第一行,枚举第一行开关的所有可能性,每个开关都是按或者不按,共2^5种,每种可能对应的情况都算一次,按3成立的条件进行,而且要保证最后第五行灯全亮,则记录次数,最后找最小次数.

5.详细的枚举递归思路:

核心:枚举第一层开关的所有状态,每个开关都有两种状态按或者不按。同时需要记录当前的开关按了的次数,还有当前开关数组的状态,因为这俩都需要记录并恢复到上一层。之后对于开关整体第一层的每种确定好的状态进行2-5层的遍历判断是否可行即可。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
/*思路:1.每个开关只用开一次,开偶数次没有用
2.顺序不影响结果
3.第一层为暗,要变亮它的下一层对应开关必须按,
即为每一层开关的状态由上一层唯一确定。
4.需要的总次数:固定第一行,枚举第一行开关的所有可能性,共2^5种,每种可能对应的情况
都算一边,按3成立的条件进行,而且要保证最后第五行灯全亮,则记录次数,最后找处最小次数.*/ 
typedef struct
{
	char g[6][6];
}sq;
sq a[501];
char change(char x)
{
	int x1=x-'0';
	char ans;
	if(x1==0) ans='1';
	if(x1==1) ans='0';
	return ans;
}
int min1=9999;
void anse(sq a,int x,int an)//a表示全部的数组,x表示第一行枚举到第几位,an记录每次的开关按动次数
//递归恢复的状态永远是前一个状态,例如当x+1>5输出时原开关数组改变了 ,但后面return到x的上一层即x=4的下面一步an++,此时开关数组未变之后仍正常走
//当前开关按的次数an也是,永远只跟前一个状态有关,即return到的那个状态 ,故按下时an++,按下完return上一层时再an--; 
{
	//第一列所有的可能,指数型枚举
	 if(x>5)
	{
	
	 	//固定一列后的枚举过程 
	for(int i=2;i<=5;i++)//行 
	{
		for(int j=1;j<=5;j++)//列 
		{
			if(a.g[i-1][j]=='0')//上一层为暗,这次必须亮
			{
				a.g[i][j]=change(a.g[i][j]);//上下左右都变色 
				a.g[i-1][j]=change(a.g[i-1][j]);
				a.g[i+1][j]=change(a.g[i+1][j]);
				a.g[i][j-1]=change(a.g[i][j-1]);
				a.g[i][j+1]=change(a.g[i][j+1]);
				an++;
	     	}
		}
	}
		int flag=0;
			for(int j=1;j<=5;j++)//判断第五行是否全亮 
			{
				if(a.g[5][j]=='0') flag=1;
			}
			if(flag==0&&an<=6&&an<min1)
			{
				min1=an;
			}
	return;	
	}
	//x<=5
	anse(a,x+1,an);
	an++;
	a.g[1][x]=change(a.g[1][x]);
	a.g[2][x]=change(a.g[2][x]);
	a.g[1][x-1]=change(a.g[1][x-1]);
	a.g[1][x+1]=change(a.g[1][x+1]);
	anse(a,x+1,an);
	an--;
}
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=5;j++)
		{
			for(int k=1;k<=5;k++)
			{
				cin>>a[i].g[j][k];
			}
		}
	}
		for(int i=1;i<=n;i++)
	{
		min1=999;//初始化最小值 
		anse(a[i],1,0);
		if(min1==999)cout<<"-1"<<endl;//无解 
	   else {cout<<min1<<endl;
	   }
	   
	}
	return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Luminous815

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值