费解的开关

题目链接:https://www.acwing.com/problem/content/97/

非常不好做的一道题,理解起来也有难度的题目

做法一:bfs

时间复杂度很高

做法二:二进制状态转移

我们先可以确定第一行是不变的,把第一行全部处理成灯亮,这样我们就可以确定第二行的状态,若对第二行进行修改则用第三行的五个方位就行了,同理

根据第三行确定第四行,根据第四行确定第五行,然后枚举第五行五个灯的状态,如果存在不亮的就说明给定的这个图是不行的

code:

 1 //具体思想:确定第一行之后来确定第二行的状态,然后是第三行,第四行,然后遍历第五行是否存在0即可
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define int long long 
 5 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
 6 const int N=30;
 7 int t;
 8 char g[N][N];
 9 const int INF=0x3f3f3f3f;
10 int dir[5][2]={
11     {-1,0},
12     {0,1},
13     {1,0},
14     {0,-1},
15     {0,0}
16 };
17 void turn(int x,int y)
18 {
19     for(int i=0;i<5;i++)
20     {
21         int dx=x+dir[i][0];
22         int dy=y+dir[i][1];
23         if(dx>=0&&dx<5&&dy>=0&&dy<5)
24         {
25             if(g[dx][dy]=='0')
26             {
27                 g[dx][dy]='1';
28             }
29             else 
30             {
31                 g[dx][dy]='0';
32             }
33         }
34     }
35 }
36 int solved(){
37     int ans=INF;
38     for(int i=0;i<1<<5;i++)//确定第一行,第一行每一个有0/1两种状态,共五个为1<<5=32
39     {
40         int res=0;//统计步数
41         char backup[N][N];//备份
42         memcpy(backup,g,sizeof(g));
43         for(int j=0;j<5;j++)//枚举第一行的五个
44         {
45             if(i>>j&1)//对应了 00010 表示第2个位置的按一下
46             //  对应了00011 表示第1 和第2个位置的按一下
47             {
48                 res++;
49                 turn(0,j);//对第j个进行变化
50             }
51         }
52         for(int j=0;j<4;j++)//枚举前4行
53         {
54             for(int k=0;k<5;k++)//枚举每一个
55             {
56                 if(g[j][k]=='0')//如果是0就变下一行与之对应的
57                 {
58                     res++;
59                     turn(j+1,k);
60                 }
61             }
62         }
63         bool flag=false;
64         for(int j=0;j<5;j++)//存在‘0’则说明变化最后还不成功
65         {
66             if(g[4][j]=='0')
67             {
68                 flag=true;
69                 break;
70             }
71         }
72         if(!flag)
73         ans=min(ans,res);
74         memcpy(g,backup,sizeof(g));//备份还原
75     }
76     if(ans>6)
77     ans=-1;
78     return ans;
79 }
80 signed main()
81 {
82     IOS;
83     cin>>t;
84     while(t--)
85     {
86         for(int i=0;i<5;i++)
87         {
88             for(int j=0;j<5;j++)
89             {
90                 cin>>g[i][j];
91             }
92         }
93         cout<<solved()<<endl;
94     }
95     return 0;
96 }

建议这道题多理解理解,多敲一下尤其是状态的二进制表示和对第一行的处理

posted @ 2023-01-03 16:05  江上舟摇  阅读(13)  评论(0编辑  收藏  举报