费解的开关

费解的开关


不得不说,这个开关真费解

这几天有点emo,沉不下心去看,连视频和题解都看不下去,后来去图书馆才好了点

现在想来,思路还是挺清晰的,最后提交错了三次,为啥呢,if的忘了加括号了,比对第三组数据才发现第34个灯有问题

下面是思路:

我们不难得到以下结论:
1.同一个开关按2下== 没按 按三下 == 按一下 => 每个开关至多按一下
2.如果一排一排来按的话,下面那排可以影响上面那排 => 这一排是否要按取决于上一排是否亮

那么由以上两个结论,我们可以得到以下思路:

首先对第一排进行全枚举
然后在第一排的各种情况下,根据 结论2 我们可以对第二排进行操作:如果这个灯的上一排不亮,那么点亮这个灯
然后每一排都这样操作
最后,遍历下最后一行,如果全亮,那么OK,反之无法点亮
途中记个数..然后.......

下面是代码:

//费解的开关 
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

char a[5][5],b[5][5];
int n,ans=7;

void light(int x,int y)
{
	int dx[5]={-1,0,0,0,1},dy[5]={0,-1,0,1,0};
	for(int i=0;i<5;i++)
	{
		int ax=dx[i]+x,ay=dy[i]+y;
		if(ax>=0&ax<5&ay>=0&ay<5)
		a[ax][ay]^=1;
	}
}

int work()
{
	ans=7;
	for(int k=0;k<1<<5;k++)//用来决定第一行每个开关是否该开 
	{
		int res=0; 
		memcpy(b,a,sizeof(a));
		for(int i=0;i<5;i++)
		{
			if((k>>i)&1)
			{
				light(0,i);
				res++;
			}
		}
		for(int i=0;i<4;i++)
		{
			for(int j=0;j<5;j++)
			if(a[i][j]=='0')
			{
				light(i+1,j);
				res++;
			}
		}
		bool success=1;
		for(int i=0;i<5;i++)
		{
			if(a[4][i]=='0')
			{
				success=0;
				break;//就是这个,被我忘了放入括号....
			}
		}
		if(success)
			ans=min(ans,res);
		memcpy(a,b,sizeof(a));
	}
	if(ans<=6)return ans;
	return -1;
}

int main()
{
	cin>>n;
	while(n--)
	{
		for(int i=0;i<5;i++)
			cin>>a[i];
		cout<<work()<<endl;
		
	}
	return 0;
}

相关问题还有POJ的Painter's Problem
这类问题有四类解法...详情看知乎大佬的分析..
知乎点灯游戏分析

posted @ 2021-09-19 22:49  qbning  阅读(112)  评论(0编辑  收藏  举报
描述