题1.费解的开关:
25 盏灯排成一个 5×5 的方形;
我们用数字 1 表示一盏开着的灯,用数字 0 表示关着的灯;
每一个灯都有一个开关,游戏者可以改变它的状态,每一步,游戏者可以改变某一个灯的状态;
游戏者改变一个灯的状态会产生连锁反应:和这个灯上下左右相邻的灯也要相应地改变其状态;
请问6步内是否可以将所有的灯变量,可以的话输出步数,不行的话输出-1。
输入格式:
第一行输入正整数 n,代表数据中共有 n个待解决的游戏初始状态;
以下若干行数据分为 n 组,每组数据有 5 行,每行 5 个字符。
通过分析题目不难发现:
1.每盏灯开关一次即可,重复两次开关相当于没操作;
2.能改变第一行灯的状态的只有第一行和第二行的灯。
枚举第一行灯的所有操作,这个时候再想要改变第一行的状态就只能开关第二行的灯了,当第二行灯的操作做完后,想要改变第二行灯的状态就只能开关第三行了......,一直到改变完最后一行的灯后,判断最后一行是全亮并且步数是否小于等于6即可。
代码如下:
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
const int N=6;
int g[N][N],tmp[N][N];//灯,并且把灯的状态复制一份
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
void f(int x,int y){//开关(x,y)
g[x][y]==0?g[x][y]=1:g[x][y]=0;
for(int i=0;i<4;i++){
int a=x+dx[i],b=y+dy[i];
if(a<0||b>=5||b<0||b>=5)continue;
g[a][b]==0?g[a][b]=1:g[a][b]=0;
}
return;
}
int main(){
int n;
cin>>n;//有n组数据
char c;
while(n--){
for(int i=0;i<5;i++)//读入
for(int j=0;j<5;j++){
cin>>c;
g[i][j]=c-'0';
}
memcpy(tmp,g,sizeof g);
int res=7;
for(int i=0;i<pow(2,5);i++){//5个二进制位
int s=0;//记录改变了几次
for(int i=0;i<5;i++)//每次将g重置
for(int j=0;j<5;j++)
g[i][j]=tmp[i][j];
for(int j=0;j<5;j++)//右移j位
if(((i>>j)&1)==1){s++;f(0,j);}
for(int k=0;k<4;k++)//枚举前4行
for(int u=0;u<5;u++){
if(g[k][u]==0){s++;f(k+1,u);}
}
for(int k=0;k<5;k++)//判断最后一行是否全亮
if(g[4][k]==0)s=7;
if(s<=6)res=min(s,res);
}
if(res>6)cout<<"-1"<<endl;
else cout<<res<<endl;
}
return 0;
}
题2.翻硬币:
桌上放着排成一排的若干硬币,用 * 表示正面,用 o 表示反面;
如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币(把翻动相邻的两个硬币叫做一步操作),那么对特定的局面,最少要翻动多少次呢?
输入格式:
两行等长的字符串,分别表示初始状态和要达到的目标状态。
输出格式:
一个整数,表示最小操作步数。
从1~n-1号硬币,确保前n-1个硬币达到目标状态,若此时最后一个硬币也处于目标状态,则找到最小步数。
代码如下:
#include<iostream>
#include<cstring>
using namespace std;
void update(char &c){
c=='*'?c='o':c='*';
}
int main(){
string str1,str2;
cin>>str1>>str2;
int n=str1.length();
int res=0;
for(int i=0;i<n-1;i++){
if(str1[i]!=str2[i]){
update(str1[i]);
update(str1[i+1]);
res++;
}
}
cout<<res;
return 0;
}