解法
注:代码在最后一起给出。
第一个想法,全状态检查,复杂度
// 500(25+O(dfs)+5)
// O(dfs)=2^25=33554432 = 310^7 = 10^7
// 15*10^9
// 10^10
解释:500个,每个开关有开和关两种可能,有25个灯,全状态设置完成后需要遍历检查。每个状态的改变影响5个灯。
第二个想法
考虑固定第一行。第一行有32种可能,在每一种可能中,对该行的改变都不能通过开关该行的灯来改变,这就是固定的含义。也就是说,第一行在当前这种可能的状态下,我们想要将其中的0改为1,只能依靠第二行,那么此时,第二行只为第一行全变为1服务,第二行某位置的主动改变只能在该位置对齐第一行的那个位置为0时。此时第二行也是固定的了。以此类推。
我说的话你可能不理解,是正常的,不过评论区全部代码的思想都是这样,那么具体代码怎么写,你应该完全依靠自己!这是及其重要的。永远不要试图理解面向过程的代码,最多读其思路
我在第一次尝试第二个想法的时候,无意间将代码写成固定列,由此猜想固定列也是没问题的
暴力全状态 代码
#include<iostream>
#include<cstring>
using namespace std;
int n;
bool is[7][7];
int result;
void change(int i,int j){
is[i][j]=!is[i][j];
is[i+1][j]=!is[i+1][j];
is[i][j+1]=!is[i][j+1];
is[i-1][j]=!is[i-1][j];
is[i][j-1]=!is[i][j-1];
}
void dfs(int i,int j,int count){
if(count>6)return;
if(i>5){
for(int j=1;j<=5;j++){
for(int k=1;k<=5;k++){
if(!is[j][k])return;
}
}
result =min(result ,count);
return;
}
if(j+1>5)dfs(i+1,1,count);
else dfs(i,j+1,count);
change(i,j);
if(j+1>5)dfs(i+1,1,count+1);
else dfs(i,j+1,count+1);
change(i,j);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=5;j++){
string s;
cin>>s;
for(int k=1;k<=5;k++){
if(s[k-1]=='1'){
is[j][k]=1;
}
else{
is[j][k]=0;
}
}
}
result=7;
dfs(1,1,0);
if(result>6)cout<<-1<<endl;
else cout<<result<<endl;
}
return 0;
}
固定行状态 代码
#include<iostream>
#include<cstring>
using namespace std;
int n;
bool is[7][7];
bool temp[7][7];
int result;
void change(bool (&num)[7][7],int i,int j){
num[i][j]=!num[i][j];
num[i+1][j]=!num[i+1][j];
num[i][j+1]=!num[i][j+1];
num[i-1][j]=!num[i-1][j];
num[i][j-1]=!num[i][j-1];
}
void work(int count){
int cnt=count;
for(int i = 1 ; i<=5;i++){
for(int j=1;j<=5;j++){
temp[i][j] = is[i][j];
}
}
for(int i=2;i<=5;i++){
for(int j=1;j<=5;j++){
if(!temp[i-1][j]){
change(temp,i,j);
cnt++;
}
}
}
for(int i = 1 ; i<=5;i++){
for(int j=1;j<=5;j++){
if(!temp[i][j])return;
}
}
result = min(result,cnt);
}
void dfs(int i,int count){
if(i>5){
work(count);
return;
}
dfs(i+1,count);
change(is,1,i);
dfs(i+1,count+1);
change(is,1,i);
}
int doit(){
dfs(1,0);
if(result>6)result=-1;
return result;
}
// 500*(25+O(dfs)) O(dfs)=2^25=33554432 = 3*10^7 = 10^7
// 15*10^9
// 10^10
//500*32*(4*5)
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=5;j++){
string s;
cin>>s;
for(int k=1;k<=5;k++){
if(s[k-1]=='1'){
is[j][k]=1;
}
else{
is[j][k]=0;
}
}
}
result=7;
cout<<doit()<<endl;
}
return 0;
}
面向过程的代码我自己写完读着都觉得恶心,如果不是赶时间,这种代码一定不能写,而是改成面向对象。
但是面向对象是很难的,需要考虑额外的(抛开题目)的东西,所以如果有人在比赛中写面向对象的代码,那么我十分想和他交朋友。
这里在第一次写change函数时,里面是写死的is。在写第二种方法时,由于temp和is都需要用,那么这其中就有复用!!!
太好了,是复用,我们有救了!!!