算法入门(一) 枚举

算法入门(一) 枚举

关灯问题 (POJ1222)

1.题目描述:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.解题分析:

可以看出当针对第一行中的开关灯的位置确定后,第一行的灯应该是处于有些灯是被熄灭,有些灯还是开启的。因为当第一行灯的开关按钮已经确定(已经确定哪些位置要按下按钮),这些第一行还亮着的灯只有通过按下第二行的灯来熄灭了!比如按完第一行的按钮后,第一行中第1,2,5列的灯还是开着的,那么要使这些灯熄灭,只有按下第二行的第1,2,5列才有可能熄灭第一行的所有灯。通过这种思路,当确定了第一行每个位置是否按下按钮后,要使得所有的灯熄灭,第二行要按下按钮的列位置已经确定,就是第一行中那些还开着灯的列。同理,当第二行的灯按下后,依然还有亮着的灯,要使这些灯熄灭,必须按下第三行对应的列位置的按钮。第四行,第五行同理。那么怎么判断我们的熄灯方案是否使得全部的灯熄灭呢?上面提到的熄灯策略一定会保证前面四行的灯全部熄灭,所以只要检查最后一行的灯是否是熄灭的就行,如果最后一行的灯也是熄灭的,那么所有灯都是熄灭的!
所以这题只需要枚举第一行(对列枚举也可)灯的熄灭策略(对应位置是否按下按钮0 0 0 0 0 0 - 1 1 1 1 1 1,1表示按下按钮)即可,因为当第一行的策略决定后,其后要是灯全部熄灭的方案同时也确定了。

3.代码:

#include<iostream>
#include<string.h>
#include<string>
using namespace std;

int light[7][8];
int tmp[7][8]={0};

void press(int i, int j)  //按下函数,用来模拟按下开关
{
	tmp[i][j]=!tmp[i][j];
	tmp[i][j-1]=!tmp[i][j-1];
	tmp[i][j+1]=!tmp[i][j+1];
	tmp[i-1][j]=!tmp[i-1][j];
	tmp[i+1][j]=!tmp[i+1][j];
}

bool check()      //只需判断最后一行灯是否灭即可
{
	int check=0;
	for(int i=1;i<=6;i++)
	{
		if(tmp[5][i]==0)
		{
			check++;
		}
	}
	if(check==6)
		return true;
	else
		return false;
}
	
int main()
{
	int cs;   //数据组数
	cin>>cs;
	
	int puzzle=0;
	while(cs--)      //输入数据
	{
		puzzle++;
		for(int i=1;i<=5;i++)
		{
			for(int j=1;j<=6;j++)
			{
				cin>>light[i][j];
			}
		}

		int button[7][8]={0};  //button用来记录按法
		int count=0;
		while(count<64)  //枚举第一排的64种按法,从000000到111111
		{
			memcpy(tmp,light,sizeof(light)); //拷贝函数

			for(int i=1;i<=6;i++)    //从第一个数开始枚举第一排的二进制数
			{
				if(button[1][i]==2)
				{
					button[1][i+1]++;
					button[1][i]=0;
				}
			}

			for(int i=1;i<=6;i++)       //按下第一行
				if(button[1][i]==1)
					press(1,i);

			for(int i=2;i<=5;i++)  //继续按
			{
				for(int j=1;j<=6;j++)
				{
					if(tmp[i-1][j]==1)  //若上一行灯没关,则下一行此位置应当关灯
					{
						press(i,j);
						button[i][j]=1;
					}
				}
			}

			if(check())  //检查最后一行灯是否全灭
			{
				cout<<"PUZZLE #"<<puzzle<<endl;
				for(int i=1;i<=5;i++)
				{
					for(int j=1;j<=6;j++)
					{
						cout<<button[i][j]<<" ";
					}
					cout<<endl;
				}
				break;
			}
			else  //若没有全灭
			{
				for(int i=0;i<7;i++)
					for(int j=1;j<=7;j++)
					{
						if(i!=1)
							button[i][j]=0;  //除第一行外清0
					}

					button[1][1]++;  //二进制数加一
					count++;
			}
		}
	}
	return 0;
}
发布了10 篇原创文章 · 获赞 7 · 访问量 340

猜你喜欢

转载自blog.csdn.net/weixin_44026026/article/details/102981944