1. 题目描述
2.思路分析
本题与郭老师本周讲解的例题熄灯问题类似,可以使用二进制表示进行枚举。每个按钮有按下、不按下两种选择(分别用0、1两个状态表示)。每个按钮最多只需要按下一次,因为连续两次按下会恢复原状态。对于每一个按钮,当其状态确定后;为使其达到目标状态,只能通过其右侧按钮进行控制。因此,最左侧按钮状态确定后,其余按钮状态随即确定。我们根据遍历过程即可确定按钮改变次数以及能否达成目标。
3.注意点
- 题目中没有给定按钮数量,我们需要根据第一行数据进行统计。
- 在某些特殊情况下,无论第一个按钮是否按下都能得到目标状态;这时要选取改变次数较少的方案作为答案。
- 需要注意边界情况,即按钮左右两个端点;本人选择将数组开大一些,两个端点对左右按钮的影响仍然在数组中使其不必特别考虑。
4.AC代码
问题分析清楚并给出坑点后,下面贴出AC代码。
#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
int lock[32];//记录密码锁初始状态
int result[32];//记录密码锁当前状态
int target[32];//记录密码锁目标状态
int method[32];//记录按钮按动方案
bool flag = false;
int init()
{
//初始化函数
char c;//记录当前读入字符
int n = 0;//记录需要处理的密码锁数量
while((c=getchar()) != '\n')
{
lock[++n] = c - '0';//字符转数字
result[n] = lock[n];
}
for(int i=1;i<=n;++i)
{
c=getchar();
target[i] = c-'0';
}
return n;
}
void set_bit(int n)
{
//按下第n位开关,并影响其两侧开关
method[n] = 1;
result[n-1] = !result[n-1];
result[n] = !result[n];
result[n+1] = !result[n+1];
}
int count_one(int n)
{
//计算按钮按动个数
int counts=0;
for(int i=1;i<=n;++i)
{
counts += method[i];
}
return counts;
}
int bin_lock(int n)
{
//从第一个开关开始实验,试探按下它后调节其余开关能否完成任务
int Min = 30;
int tmp;
method[1] = 0;//第一个按钮不按下
for(int i=2;i<=n;++i)
{
if(result[i-1] != target[i-1])
{
set_bit(i);
}
}
if(result[n] == target[n])
{
//当前方案成功
flag = 1;
tmp = count_one(n);
if(tmp<Min) Min = tmp;
}
//恢复现场
for(int i=1;i<=n;++i)
{
result[i] = lock[i];
method[i] = 0;
}
method[1] = 1;//第一个按钮按下
set_bit(1);
for(int i=2;i<=n;++i)
{
if(result[i-1] != target[i-1])
{
set_bit(i);
}
}
if(result[n] == target[n])
{
//当前方案成功
flag = 1;
tmp = count_one(n);
if(tmp<Min) Min = tmp;
}
return Min;
}
int main()
{
int n = init();//n为按钮数量
int Min = bin_lock(n);
if(flag) cout<<Min;
else cout<<"impossible";
return 0;
}