题目链接: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 }
建议这道题多理解理解,多敲一下尤其是状态的二进制表示和对第一行的处理
标签:第一行,int,费解,第三行,确定,开关,第四行,第二行 From: https://www.cnblogs.com/LQS-blog/p/17022545.html