Openjudge 2811 熄灯问题 枚举 爆搜

熄灯问题链接如下 http://bailian.openjudge.cn/practice/2811/

该题尝试得到一组开关的状态使得灯全部被熄灭,经过分析容易得到,我们枚举第一行开关的状态后,为了达到目的,剩下所有行的开关的状态都是固定的且是由第一行开关的状态推导出来的,因为第一行开关状态固定后,可以影响第一行灯的状态的只有第二行开关的状态了,以此类推,到确定最后一行灯的状态后我们就可以验证最后得到的灯的状态是不是理想的状态了

本题有两个坑,一个是如何枚举第一行灯的状态,得到一个全排列,一种方法是最暴力的,多个for循环叠加,但是如果该行个数比较多的时候就不可行,另一种方法则是利用回溯(递归?)来生成第一行的状态,第二个坑则还是初始化的问题,切记,当我们处理完状况1,又处理状况2的时候,要把能想到的所有的初始化都做了,这里我一开始没有清空send数组导致一直出错。。。同样的错误不可以犯第三次了

代码如下

递归生成全排列版本:

#include <memory.h>
#include<stdio.h>
#include<iostream>
#include<math.h>
using namespace std;
int button[6] ;
int send[10][10];
int a[10][10];
int b[10][10];
int dx[5] = {0,0,1,-1,0};
int dy[5] = {1,-1,0,0,0};
bool done;
bool check() //检查是否全熄灭
{
	for (int i = 0; i < 5; i++)
		for (int j = 0; j < 6; j++)
			if (b[i][j] == 1) return false; //b[i][j]=1代表这个灯是点亮的
	return true;
}

void op(int x, int y) //根据开关进行操作
{
	int x1, y1;
	for (int i = 0; i < 5; i++)
	{
		x1 = x + dx[i]; y1 = y + dy[i];
		if (x1 >= 0 && x1 < 5 && y1 >= 0 && y1 < 6) b[x1][y1] = !b[x1][y1];
	}
}

void work() //找到一组第一行的状态后,进行操作
{
	memset(send, 0, sizeof(send));   //必须初始化send数组,否则之前开关的状态会影响到现在
	for (int i = 0; i < 5; i++)
		for (int j = 0; j < 6; j++)
			b[i][j] = a[i][j];   //初始化b数组使得其与a数组相同

	for (int i = 0; i < 6; i++)
		send[0][i] = button[i];

	for (int i = 0; i < 4; i++)               //对除最后一行外的灯操作
	{
		for (int j = 0; j < 6; j++)			 //按照搜索出来的状态,熄灯操作
			if (send[i][j] == 1) op(i, j);   //send[i][j]==1 代表这里要按下去,即改变状态
		for (int j = 0; j < 6; j++)				//根据当前行灯的状态,决定下一行的操作
			if (b[i][j] == 1) send[i + 1][j] = 1;
	}
	for (int j = 0; j < 6; j++) if (send[4][j] == 1) op(4, j); //对最后一行进行操作
	
	if (check() == true)
	{
		done = true;
		
	}
}

void product_button(int x)
{
	if (done) return;
	button[x] = 0;
	if (x+1<6) product_button(x + 1);
	else work(); //枚举出一种第一行开关状态,进行判断
	if (done) return;
		
	button[x] = 1;
	if (x+1<6) product_button(x + 1);
	else work();  //枚举出一种第一行开关状态,进行判断
	if (done) return;
}

void solve()
{
	product_button(0);
		
}

int main()
{
	for (int i = 0; i < 5; i++)
		for (int j = 0; j < 6; j++)
			cin >> a[i][j];

	done = false;
	solve();

	
	
	
	
	for (int i = 0; i < 5; i++)
	{
		for (int j = 0; j < 6; j++) 
			if (j==0) cout << send[i][j];
			else cout << " " << send[i][j];
	    cout << endl;
	}
	
    return 0;
}

程设期末上机考试有一道类似的题,还没有做出来,明天想一想

题目链接:http://cxsjsx.openjudge.cn/final2015/J/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值