pku_oj: 8469特殊密码锁(C++)

问题描述

有一种特殊的二进制密码锁,由n个相连的按钮组成(n<30),按钮有凹/凸两种状态,用手按按钮会改变其状态。

然而让人头疼的是,当你按一个按钮时,跟它相邻的两个按钮状态也会反转。当然,如果你按的是最左或者最右边的按钮,该按钮只会影响到跟它相邻的一个按钮。

当前密码锁状态已知,需要解决的问题是,你至少需要按多少次按钮,才能将密码锁转变为所期望的目标状态。

输入两行,给出两个由0、1组成的等长字符串,表示当前/目标密码锁状态,其中0代表凹,1代表凸。输出至少需要进行的按按钮操作次数,如果无法实现转变,则输出impossible。

样例输入

011
000

样例输出

1



分析:
通过枚举来解决这个问题,通过对问题分析,首先可以得到两个结论:
1.对于一个按钮,实际上只有两个状态:开/关,对应一个按钮 按/不按,即每个按钮最多只按一次
2.各个按钮被按下的顺序对最终的结果没有影响
总体思路:
我们最终的目的是让两组按钮序列对应相等,等价于所有相对应的两个按钮相等因此,我们可以约定一个顺序,比如从左到右分析,依次比较每个字符,
如果相等则比较下一个,如果不等,有两种方法可以翻转状态:一是按下当前按钮,二是按下下一个按钮。对于前者,同时翻转前一个按钮(除去一个特殊情况,见下方),
对于后者,对前一个按钮不影响。*特殊情况:当第一个按钮不同时,如果采取第一个翻转办法,对前一个(实际不存在)按钮无影响,
而从第二个按钮开始,如果还采取第一种方法,对前一个按钮会有影响,因此,从第二个按钮开始必须采用翻转后一个按钮的办法。
*说明:从上述总体思路可知,如果从第二个按钮开始,仍要采取第一个翻转方法的话,必然破坏了前面按钮的一致性,如果就此继续分析,要恢复前面按钮的一致性,不外乎三种方法
其一,按下前面按钮的左边,其二,按下前面按钮,其三,按下当前按钮(此时当前按钮已经按了两次)
对于第一种办法,问题的规模又开始向着原始规模恢复,无法得到解对于第二种办法,可能规模向着原始规模恢复,而且重置了后一个按钮的状态
综上,得到结论:除了第一个按钮,其他所有按钮要改变其状态,只能通过其后的按钮状态来改变其状态(对应于从左到右分析的约定)
简言之:对于第一个按钮,分类讨论:1.按下当前按钮  2.按下下一个按钮对于其他按钮,只能是按下下一个按钮
代码如下:
 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 
 5 void Flipone(char& s);    //翻转单个元素
 6 int Getmin(int*);        //取最小次数
 7 
 8 int cnt[2] = { 0 };
 9 
10 int main()
11 {
12     char a[35], b[35], c[35];
13     cin >> a >> b;
14     int len = strlen(a);
15     for (int p = 0; p < 2; ++p) {        //两种情况分别讨论
16         strcpy(c, a);
17         if (p == 1) {
18             Flipone(c[0]);
19             Flipone(c[1]);
20             cnt[p]++;
21             if (strcmp(b, c) == 0)
22                 goto flag;
23         }
24         for (int i = 0; i < len - 1; ++i) {        
25             if (c[i] != b[i]) {
26                 Flipone(c[i]);
27                 Flipone(c[i+1]);
28                 if (i+2 < len) {
29                     Flipone(c[i + 2]);
30                 }
31                 cnt[p]++;
32                 if (strcmp(b, c) == 0)
33                     goto flag;
34             }
35         }
36     }
37 flag:
38     int cnt_min = Getmin(cnt);
39     if (strcmp(b, c) == 0)
40         cout << cnt_min << endl;
41     else
42         cout << "impossible" << endl;
43 }
44 
45 void Flipone(char& s)
46 {
47     if (s == '0')
48         s = '1';
49     else
50         s = '0';
51 }
52 
53 int Getmin(int* cnt)
54 {
55     if (cnt[0] > cnt[1])
56         return cnt[1];
57     else
58         return cnt[0];
59 }
 

*注意:不建议使用goto语句

 

猜你喜欢

转载自www.cnblogs.com/laideng/p/11370261.html