目录
递推
Acwing 95. 费解的开关
题目
思路
这题的大概思路有两个:dfs和递推。 如果使用dfs来做的话,可能会超时。
下面我们看看递推的大致思路:
首先我们这道题的目的是让每个灯都变亮,我们会发现其实每个灯之间都是有关系的,如果有一个灯不亮,那么他周围的灯就需要改变状态来让他变亮,但如果就这样思考的话,肯定不行,我们可以先把第一行固定下来,利用第一行的状态来递推下面几行的状态情况:首先第一行有5个灯,一共会有2^5也就是32种不同的状态,然后利用第二行和第一行的关系,去让第一行的灯全部变亮,这时第一行全部变亮了,之后再利用第三行与第二行的关系,让第二行全部变亮,以此类推,直到最后一行之前,我们都可以利用后一行与前一行的关系,让前一行变亮,但是最后一行已经没有后一行了,所有最后一行成为了判断是否全亮的标准,如果此时最后一行也是全部都亮的,那么就说明此时枚举的这种状态可以成功,但不一定是最简的,所有程序中要维护一个最小变量。
注意点
这里面有一个困扰我很久的地方:为什么是k>>i&1的时候进入if,不应该是灯不亮的时候进去if,然后利用turn函数让它变量吗?其实并不是这样的,这说明我对k还没有理解,k是用来枚举第一行的32种不同状态的,例如:如果k=0,换成5位的二进制也就是00000,这里的0表示状态不需要发生变化,如果k=1,二进制也就是00001,表示最后一个位置要发生变化。
代码
#include<iostream>
#include<cstring>
using namespace std;
const int N=6;
char p[N][N],temp[N][N];
int dx[5]={
-1,1,0,0,0},dy[5]={
0,0,-1,1,0};
void turn(int a,int b)
{
for(int i=0;i<5;i++)
{
int na=a+dx[i],nb=b+dy[i];
if(na<0||na>=5||nb<0||nb>=5) continue;
else
{
p[na][nb]^=1; // 因为‘0’的阿斯克码为48,而1为49,只有一位不同,所有可以这么做。
}
}
}
int main()
{
int t=0;
cin>>t;
while(t--)
{
for(int i=0;i<5;i++)
{
cin>>p[i];
}
int res=10;
for(int k=0;k<32;k++)
{
int step=0; //注意这个step要写在循环里面,因为针对每种情况step都要重新计算,以求出最小值。
memcpy(temp,p,sizeof p);
for(int i=0;i<5;i++) //枚举第0行的32种不同的状态
{
if(k>>i&1) //这里的k代表32种不同的状态,1表示与原来的状态不同,0表示与原来的状态相同
{
step++;
turn(