先贴个题目:
以及原题链接:
95. 费解的开关 - AcWing题库https://www.acwing.com/problem/content/97/ 以及我的代码:
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
char a[5][5];
char backup[5][5];
void turn(int x,int y){ //开关函数
int n[5] = {-1, 0, 0, 0, 1}, m[5] = {0, 0, -1, 1, 0}; //偏移量
for (int i = 0; i < 5;++i){
int xx = x + n[i], yy = y + m[i];
if(xx<0||xx>4||yy<0||yy>4) //防止数组越界
continue;
else{
if(a[xx][yy]=='1')
a[xx][yy] = '0';
else
a[xx][yy] = '1';
}
}
return;
}
int main()
{
int T;
cin >> T;
for (int ii = 0;ii<T;++ii){
int step = 0,Min = 7;
for (int i = 0; i < 5; ++i)
for (int j = 0; j < 5; ++j)
cin >> a[i][j];
memcpy(backup, a, sizeof(a)); //贮存原状态
for (int i = 0; i < 32;++i){ //第一行枚举
step = 0;
memcpy(a, backup, sizeof(a));
for (int j = 0; j < 5;++j)
if(i>>j&1){
turn(0, j);
step++;
}
for (int j = 1; j < 5;++j)
for (int k = 0; k < 5;++k)
if (a[j - 1][k]=='0'){
turn(j, k);
step++;
}
int sign = 1;
for (int i = 0; i < 5;++i)
if(a[4][i]=='0'){
sign = 0;
break;
}
if(sign)
Min = min(step, Min); //取最小步数
}
if(Min>6)
Min = -1;
cout << Min<<endl;
}
return 0;
}
这题基本是用到了递推和枚举,阅读题目后最关键的解题思路在于发现了三个规律:1.每个灯的选择只有按1次或者不按2.每个灯按的顺序不影响最后结果3.一行状态定完只有下一行能改变,即第一行确定则第二行固定,第二行固定则第三行固定,所以只需要枚举第一行即可。然后在
for (int i = 0; i < 32;++i){
for (int j = 0; j < 5;++j)
if(i>>j&1){
turn(0, j);
step++;
}
这里,我利用二进制思想,将10进制0-31看作一行灯的开关状态,然后利用位运算来判断是否需要摁开关。然后因为1-4行必须灯全亮,只需在枚举最后判断最后一行是否灯全亮即可。
by————2024.1.29刷题记录