算法_枚举局部解空间

枚举

一、概念

策略:遍历所有解空间,逐个验证答案。

思路:对于实际问题,枚举所有可能解的代价可能很大。如果存在某个局部,一旦局部确定,其余部分唯一确定,那么只需要枚举此局部状态即可。

二、案例

案例网址:http://cxsjsxmooc.openjudge.cn/2018t2winterw1/001/

总时间限制: 

1000ms

内存限制: 

1024kB

描述

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

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

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

输入

两行,给出两个由0、1组成的等长字符串,表示当前/目标密码锁状态,其中0代表凹,1代表凸。

输出

至少需要进行的按按钮操作次数,如果无法实现转变,则输出impossible。

样例输入

011

000

样例输出

1

 

三、案例解析

1.n<30,全部枚举空间约为536,870,912种,无法在规定时间1000ms内验证完毕。

2.事实上,除了第一个和最后一个按钮,按下中间的任何一个按钮,均会改变相邻两个按钮状态,因此如果某一位置按钮与目标密码锁状态不同,前一位置状态已经相同,则均不得按下此位置按钮,可以通过按下此位置的后一位置按钮来达到目的。

3.第一个按钮是否按下,直接决定了整个密码锁后续按钮是否需要按下。枚举空间为2,而不是229

 

四、源代码

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 void Flip(char c[], int i)
 5 {
 6     // 按下第i个按钮,修改状态
 7     c[i] = c[i] ^ 1; 
 8     if(i == 0)
 9     {
10         c[1] = c[1] ^ 1;
11     }
12     else if(i == 29)
13     {
14         c[28] = c[28] ^ 1;
15     }
16     else
17     {
18         c[i+1] = c[i+1] ^ 1;
19         c[i-1] = c[i-1] ^ 1;
20     }
21 }
22 int main()
23 {
24     char origin[30];
25     char temp[30];
26     char result[30];
27     int switchs[30];
28     cin >> origin >> result;
29     int len = strlen(origin);
30     for(int one =0; one <2; one++)
31     {
32             for(int i=0; i<len; i++)
33             {
34                 temp[i] = origin[i];
35                 switchs[i] = 0;
36             }
37         if(one == 0)
38         {
39             //第一个按钮不需要按下
40             for(int j=0; j<len-1; j++)
41             {
42                 if(temp[j] != result[j])
43                 {
44                     Flip(temp, j+1);
45                     switchs[j+1] = 1;
46                 }
47              }
48              if(temp[len-1] == result[len-1])
49                  break; 
50         }
51         if(one == 1)
52         {
53             //第一个按钮需要按下
54             Flip(temp, 0);
55             switchs[0] = 1;
56             for(int j=0; j<len-1; j++)
57             {
58                 if(temp[j] != result[j])
59                 {
60                     Flip(temp, j+1);
61                     switchs[j+1] = 1;
62                 }
63              }
64              if(temp[len-1] == result[len-1])
65                  break; 
66         }        
67     }
68     if(temp[len-1]==result[len-1])
69     {
70         int n=0;
71         for(int i=0; i<len; i++)
72         {
73             n = n + switchs[i]; 
74         }
75         cout << n;
76     }
77     else 
78     {
79         cout << "impossible" << endl;
80     }
81     return 0;
82 }

五、更多

1.取字符c的第i位:(c >> i) & 1;

2.设置字符c的第i位为1:c |= (1 << i);  设置字符c的第i位为0:c &= ~(1 << i); 

3.将c的第i位取反:c  ^= (1 << i);

posted @ 2018-09-18 00:00  yaoone  阅读(734)  评论(0编辑  收藏  举报