AcWing95. 费解的开关 枚举+位运算
这道题的确比较难想,首先我们知道图比较小,有可能是枚举,那么该如何枚举呢???
你可以发现,我们只要把第一排定了,并且保证第一排不准动,那么答案就定了
也就是说,我们首先用二进制枚举,枚举第一行需要翻转的,然后让第一行不准再翻转,后面的翻转只能在第二行进行,那么第二翻转的实际上是定好了的,然后因为定好了,所以不能翻转,那么第二行也定了,我们要改变第二行,只能通过第三行,最后判断一下最后一位是不是0就好了,做法的话,可以把每一行用一个数字保存,然后进行异或操作,对某位的1或者0进行操作,或者笨一点开二维数组。
#include <bits/stdc++.h> using namespace std; char str[10][10]; const int INF = 0x3f3f3f3f; int main(){ int t; scanf("%d",&t); char s[10][10]; int a[5]; while(t--){ memset(a,0,sizeof(a)); for (int i=0;i<5;i++){ scanf("%s",s[i]); int ss=16; for (int j=0;j<5;j++){ if (s[i][j]=='0'){ a[i]+=ss; } ss=ss/2; } } int b[5]; int ans=INF; for (int i=0;i<(1<<5)-1;i++){ for (int j=0;j<5;j++){ b[j]=a[j]; } int cnt=0; for (int j=0;j<5;j++){ if((i>>j)&1){ cnt++; b[0]=b[0]^(1<<j); b[1]=b[1]^(1<<j); if (j+1<5){ b[0]=b[0]^(1<<(j+1)); } if (j-1>=0){ b[0]=b[0]^(1<<(j-1)); } } } for (int j=1;j<5;j++){ for (int k=0;k<5;k++){ if((b[j-1]>>k)&1){ b[j-1]=b[j-1]^(1<<k); b[j]=b[j]^(1<<k); cnt++; if (k+1<5){ b[j]=b[j]^(1<<(k+1)); } if (k-1>=0){ b[j]=b[j]^(1<<(k-1)); } if (j+1<5){ b[j+1]=b[j+1]^(1<<(k)); } } } } int flag=0; for (int j=0;j<5;j++){ if (b[j]!=0){ flag=1; break; } } if (flag==0){ ans=min(ans,cnt); } } if (ans<=6){ printf("%d\n",ans); }else { printf("-1\n"); } } return 0; }
有不懂欢迎咨询
QQ:1326487164(添加时记得备注)