问题描述
有一种特殊的二进制密码锁,由n个相连的按钮组成(n<30),按钮有凹/凸两种状态,用手按按钮会改变其状态。然而让头疼的是,当你按一个按钮时,跟它相邻的两个按钮状态也会反转。当然,如果你按的是最左或者最右边的按钮,该按钮只会影响到跟它相邻的一个按钮。当前密码锁状态已知,需要解决的问题是,你至少需要按多少次按钮,才能将密码锁转变为所期望的目标状态。
输入
两行,给出两个由0、1组成的等长字符串,表示当前/目标密码锁状态,其中0代表凹,1代表凸。
输出
至少需要进行的按按钮操作次数,如果无法实现转变,则输出 impossible。
样例输入
011
000
样例输出
1
我の思考
此题想要用枚举法来解决,那我们就应该找出可能的几种情况。我们研究过这个机制后会发现,影响按钮改变的其实就是周围的按钮。但是在这里,我们会发现,第一个按钮的按与否,会影响到后面所有的按钮,也就是说,这里的枚举是枚举出当按下第一个按钮和不按第一个按钮的情况。而其他的,就只要找到一个不和目标对应为相等的按钮,我们按下它的下一个即可。
我の代码
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
int result=1<<30;
int result2=0;
int len=0;
void flipNum(char* a,int i){
if(a[i] == '1'){
a[i] ='0';
}
else {
a[i] = '1';
}
}
//比较是否相同
int cmpNum(char* a,char* b){
int i=0;
for(;i<len;i++){
if(a[i]!=b[i]){
return false;
}
}
return true;
}
//设置反转
void setArray(char* a,int i){
flipNum(a,i);
if(i == 0){
flipNum(a,i+1);
} else {
flipNum(a,i-1);
flipNum(a,i+1);
}
result2++;
}
//获取次数最小的
int minNum(int i,int j){
if(i<j)
return i;
else
return j;
}
int main()
{
char origin[35];
char aim[35];
cin>>origin;
cin>>aim;
len = strlen(origin);
//处理数据
if(cmpNum(origin,aim)){
result = minNum(result,result2);
return 0;
}
char c[35];
for(int p=0;p<2;p++){
result2=0;
memcpy(c,origin,len);
if(p==1){
setArray(c,0);
if(cmpNum(c,aim)){
result = minNum(result,result2);
}
}
for(int i=0;i<len-1;i++){
if(c[i] != aim[i]){
setArray(c,i+1);
if(cmpNum(c,aim)){
result = minNum(result,result2);
}
}
}
}
if(result == 1<<30)
cout<<"impossible";
else
cout << result;
return 0;
}
我の小结
此外,因为我也算是一个算法学习上的新人,在很多细节处理的地方都不好。通过这个例子,我应该注意到,如果是最小的次数,一定要记得把所有的情况都经历过一次,再取最小的。还有数组设置长度的时候,最好设大一点点,可以提高容纳错误的能力,另外就是一些常用函数的对应头文件啊之类的要记忆一下QAQ。