问题描述
有一种特殊的二进制密码锁,由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。