🐾或许会很慢,但是不可以停下🐾
题目
收获
- vector+pair的用法
- 先算时间复杂度,是否枚举,没法子也枚举吧
- 位运算tql了
补充知识
(1)左移运算符 (<<):
用途: 将整数的二进制表示向左移动指定位数,用0填充空位。
示例: 1 << 16 将1左移16位,生成一个代表65536的二进制数,用于表示16个灯泡的所有可能状态。
(2)右移运算符 (>>):
用途: 将整数的二进制表示向右移动指定位数,左侧空位填充取决于符号位。
示例: op >> get(i,j) > 根据位置(i,j)右移op,用于检查特定灯泡的开关状态。
(3)与运算符 (&):
用途: 对两个数的二进制表示进行位与操作,只有当两位都为1时结果位才为1。
示例: op >> get(i,j) & 1 > 用于确定经过右移操作后的数的最低位是否为1,从而决定是否执行开关操作。
题解
#include<bits/stdc++.h>
using namespace std;
//2^16=65536 直接暴力枚举
//op表示每个位置的状态进行枚举
//最后判断是否全open
//使用vector记录路径
char g[4][4],bk[4][4];
typedef pair<int,int> PII;
vector<PII> res,tem;
void turn(int x,int y)
{
for(int i=0;i<4;i++)
{
if(g[i][y]=='-') g[i][y]='+';
else g[i][y]='-';
}
for(int i=0;i<4;i++)
{
if(g[x][i]=='-') g[x][i]='+';
else g[x][i]='-';
}
if(g[x][y]=='-') g[x][y]='+';
else g[x][y]='-'; //两次没反过来,再反一次
}
int get(int i,int j)
{
return i*4+j;
}
int main()
{
for(int i=0;i<4;i++)
cin>>g[i];
for(int op=0;op<1<<16;op++) //16个位置的状态
{
memcpy(bk,g,sizeof g);
//operation
for(int i=0;i<=3;i++)
for(int j=0;j<=3;j++)
if(op>>get(i,j)&1) //该位置是1,进行反转
turn(i,j),tem.push_back({i,j});
//judge
int flag=0;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(g[i][j]=='+')
flag=1;
//update
if(flag==0) //操作成功 全亮了
{
//如果方案为空或者他的操作数大于我们刚存好的新的方案,那么就修改它
if(res.empty()||res.size()>tem.size()) res=tem;
}
tem.clear();
//复原
memcpy(g,bk,sizeof bk);
}
cout<<res.size()<<endl;
for(int i=0;i<res.size();i++)
{
cout<<res[i].first+1<<' '<<res[i].second+1<<endl;
}
return 0;
}