费解的开关(递推位运算)

文章描述了一个编程竞赛中的问题,给定一个5x5的矩阵,每步操作可以改变一个灯泡及其相邻灯泡的状态。目标是在不超过6次操作内打开所有灯泡。解决方案包括固定第一行的状态,然后通过枚举第一行所有可能的操作,使用DFS或二进制枚举方法递归处理后续行,找到最小操作数。若无法在6步内完成,则输出-1。
摘要由CSDN通过智能技术生成

看了y总的蓝桥杯,再加深一下印象。

题意

给你一个5*5的矩阵有25盏灯,你需要把所有的灯都打开,如果你要改变一个灯的状态那么这个灯上下左右的状态都会被改变,如果能在6操作内把所有的灯打开,请输出最小操作数,否咋输出-1。

思路

首先每个灯最多改变一次状态。
如果我们固定第一行的状态,那么我们可以得出每一行开关的操作完全被前一行灯的亮灭状态决定。
如果第一行进行操作过后是10110那么第二行的第1,3,4列是不能操作了,一旦操作对应的第一行的灯就会关闭,操作就冗余了。

所以我们只需要枚举第一行的所有操作,然后依次往下递推就是了,第一行一共就有 2 5 = 32 2^5 = 32 25=32种,可以采取dfs,或者二进制枚举来。

#include<bits/stdc++.h>

#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long 
#define endl "\n"

using namespace std;

const int N = 10;
const int dx[] = {-1, 0, 1, 0, 0};
const int dy[] = { 0, 1, 0, -1, 0};

int n, m, k, _;
char arr[N][N], backup[N][N];
int res;

void turn(int x, int y)
{
	for (int i = 0; i < 5; i++)
	{
		int a = x + dx[i], b = y + dy[i];
		if (a < 0 || a >= 5 || b < 0 || b >= 5) continue;
		arr[a][b] ^= 1;
	}
}

void solve()
{
	//枚举第一行的操作。
	//每一行开关的操作完全被前一行灯的亮灭状态决定。

	res = 10;
	for (int i = 0; i < 5; ++i) cin >> arr[i];
	
	for (int op = 0; op < 32; ++op)
	{
		memcpy(backup, arr, sizeof backup);
		int step = 0; 
		for (int i = 0; i < 5; i++)
		{
			if (op >> i & 1)
			{
				step++;
				turn(0, i);
			}
		}

		for (int i = 0; i < 4; i++)
		{
			for(int j = 0; j < 5; j ++)
			if (arr[i][j] == '0')
			{
				step++;
				turn(i + 1, j);
			}
		}

		bool f = 1;

		for (int i = 0; i < 5; i++)
		{
			if (arr[4][i] == '0')
			{
				f = 0;
				break;
			}
		}

		if (f) res = min(res, step);
		memcpy(arr, backup, sizeof arr);
	}

	if (res > 6) res = -1;
	cout << res << endl;
}

signed main()
{
	IOS;
	cin >> _;
	while (_--)
		solve();
	return 0;
}```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值