AcWing95 费解的开关 (递推)
题目链接:https://www.acwing.com/problem/content/description/97/
有几个重要性质:
- 每个位置最多被点击一次
- 若第一行状态固定,那么满足题目要求的点击方案最多只有一种
- 点击的先后顺序不影响最终结果
于是将每行的状态用二进制数存储,枚举第一行的点击状态,然后向下递推
题目问的是能否\(6\)步以内完成,要注意读题。。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<stack>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 10;
int n;
int a[maxn],b[maxn];
char s[maxn];
int t[maxn];
void print(int w){
memset(t,0,sizeof(t));
int cnt = 0;
while(w){
t[++cnt] = w & 1;
w >>= 1;
}
for(int i=5;i>=1;--i) printf("%d",t[i]); printf("\n");
}
bool check(int x){
for(int i=0;i<5;++i){
if(!((x>>i) & 1)) return false;
}
return true;
}
int solve(int S){
memset(b,0,sizeof(b));
for(int i=1;i<=5;++i) b[i] = a[i];
int cnt = 0;
for(int i=0;i<5;++i){
if((S>>i) & 1){
++cnt;
b[1] ^= (1<<i);
b[2] ^= (1<<i);
b[1] ^= (1<<(i+1));
b[1] ^= (1<<(i-1));
}
}
for(int i=2;i<=5;++i){
for(int j=0;j<5;++j){
if(!((b[i-1]>>j) & 1)){
++cnt;
b[i-1] ^= (1<<j);
b[i] ^= (1<<j);
b[i+1] ^= (1<<j);
b[i] ^= (1<<(j+1));
b[i] ^= (1<<(j-1));
}
}
}
if(check(b[5])) return cnt;
else return -1;
}
ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
int main(){
n = read();
while(n--){
for(int i=1;i<=5;++i) a[i] = 0;
for(int i=1;i<=5;++i){
scanf("%s",s);
for(int j=0;j<5;++j){
a[i] = (a[i] << 1) + s[j] - '0';
}
}
int ans = 1000000007, flag = 0;
for(int S=0;S<(1<<5);++S){
int res = solve(S);
if(res != -1){
flag = 1;
ans = min(ans, res);
}
}
if(!flag || ans > 6){
printf("-1\n");
}else{
printf("%d\n",ans);
}
}
return 0;
}