枚举-熄灯问题

题目链接:http://bailian.openjudge.cn/practice/2811/

题面

题目描述:有一个由按钮组成的矩阵,其中每行有6个按钮,共5行。每个按钮的位置上有一盏灯。当按下一个按钮后,该按钮以及周围位置(上边、下边、左边、右边)的灯都会改变一次。即,如果灯原来是点亮的,就会被熄灭;如果灯原来是熄灭的,则会被点亮。在矩阵角上的按钮改变3盏灯的状态;在矩阵边上的按钮改变4盏灯的状态;其他的按钮改变5盏灯的状态,

输入
5行组成,每一行包括6个数字(0或1)。相邻两个数字之间用单个空格隔开。0表示灯的初始状态是熄灭的,1表示灯的初始状态是点亮的。
输出
5行组成,每一行包括6个数字(0或1)。相邻两个数字之间用单个空格隔开。其中的1表示需要把对应的按钮按下,0则表示不需要按对应的按钮。

暴力解法:我们可以枚举出所有按钮可能的种类,按钮一共有2^30种可能复杂度太高不过多赘述。

优化枚举
假设(i,j)(第i行第j列)处的灯处于点亮的状态,我们改变(i,j+1)处开关的状态就可以熄灭(i,j)处的灯并且不会对第j列的其他位置造成影响,这样除了最后一列之外的灯就可以全部处于熄灭的状态。
所以我们可以只通过枚举第一列开关的状态再用以上操作进行展开只要最后一列的灯都处于熄灭的状态这就是我们所需要的答案

点击查看代码
#include <bits/stdc++.h>
using namespace std;

#define int long long
typedef pair<int, int> pll;
int dx[] = {0, 1, 0, -1, 0};
int dy[] = {0, 0, 1, 0, -1};
int arr[10][10];
int judge[10];
void dfs(int x)
{
if (x == 6)
{
int ans[10][10] = {0};
int arr1[10][10] = {0};
for (int i = 1; i <= 5; i++)
{
for (int j = 1; j <= 6; j++)
{
arr1[i][j] = arr[i][j];
}
}
for (int i = 1; i <= 5; i++)
{
if (judge[i] == 1)
{
ans[i][1] = 1;
for (int j = 0; j < 5; j++)
{
if (arr1[i + dx[j]][1 + dy[j]])
arr1[i + dx[j]][1 + dy[j]] = 0;
else
arr1[i + dx[j]][1 + dy[j]] = 1;
}
}
}
for (int j = 2; j <= 6; j++)
{
for (int i = 1; i <= 5; i++)
{
if (arr1[i][j - 1] == 1)
{
if (ans[i][j])
ans[i][j] = 0;
else
ans[i][j] = 1;
for (int k = 0; k < 5; k++)
{
if (arr1[i + dx[k]][j + dy[k]])
arr1[i + dx[k]][j + dy[k]] = 0;
else
arr1[i + dx[k]][j + dy[k]] = 1;
}
}
}
}
for (int i = 1; i <= 5; i++)
{
if (arr1[i][6] == 1)
return;
}
for (int i = 1; i <= 5; i++)
{
for (int j = 1; j <= 6; j++)
{
cout << ans[i][j] << " ";
}
cout << endl;
}
exit(0);
}
judge[x] = 1;
dfs(x + 1);
judge[x] = 0;
dfs(x + 1);
}
void solve()
{
for (int i = 1; i <= 5; i++)
{
for (int j = 1; j <= 6; j++)
{
cin >> arr[i][j];
}
}
dfs(1);
}
signed main()
{
int t = 1;
// cin>>t;
while (t--)
{
solve();
}
return 0;
}`
posted @ 2025-08-06 19:57  zznu_ybk  阅读(43)  评论(0)    收藏  举报