第1周测验题解-特殊密码锁

1. 题目描述

在这里插入图片描述

2.思路分析

本题与郭老师本周讲解的例题熄灯问题类似,可以使用二进制表示进行枚举。每个按钮有按下、不按下两种选择(分别用0、1两个状态表示)。每个按钮最多只需要按下一次,因为连续两次按下会恢复原状态。对于每一个按钮,当其状态确定后;为使其达到目标状态,只能通过其右侧按钮进行控制。因此,最左侧按钮状态确定后,其余按钮状态随即确定。我们根据遍历过程即可确定按钮改变次数以及能否达成目标。

3.注意点

  1. 题目中没有给定按钮数量,我们需要根据第一行数据进行统计。
  2. 在某些特殊情况下,无论第一个按钮是否按下都能得到目标状态;这时要选取改变次数较少的方案作为答案。
  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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值