吴昊品游戏核心算法 Round 7 —— 熄灯游戏AI(有人性的Brute Force)(POJ 2811)
暴力分为两种,一种属于毫无人性的暴力,一种属于有人性 的暴力。前面一种就不说了,对于后面一种情况,我们可以只对其中的部分问题进行枚举,而通过这些子问题而推导到整个的问题中。我称之为有人性的Brute Force。这次的熄灯问题就采用了这一点,将原本时间复杂度为O(2^30)的问题降为O(2^6),虽然都是属于指数级别的问题,但是,由于巧妙地运 用了数据之间的规律,而将复杂程度大为降低。这样做避免了毫无人性的暴力,让计算机在解决问题的时候也轻松了许多。
如图所示,这是一款在android手机上运行的Lights Off小游戏,我们可以看到,该游戏更换了一些皮肤,界面还是传统型的,游戏的关键在于将所有的灯都熄灭。
如图,显示出了该游戏的一些规则:
我们可以看到,如果一个一个实验的话,将会存在2^30次方的可能性。但是,我们很快就发现,数据之间是存在规律的,你如果可以确定第一行的全部状态,其 将直接地影响到第二行乃至第五行的状态。由于第五行是无法进行最后的调整的,所以,我们只需要判断第五行是否存在有完全熄灭的可能,这样,问题的复杂度就 降低到了2^6,就具备一定的可解性了!
在给出有注释的源代码之前(此问题来自POJ),我还是说下亮点吧:
(1) 为什么我们之前要增加三个方向的哨兵位(0位)?是因为,这样的话,我们可以统一地调用这样的公式:press[r+1][c]=(puzzle[r] [c]+press[r][c]+press[r-1][c]+press[r][c-1]+press[r][c+1])%2;
(2)在枚举函数enumate()中,我们可以将第一行的情况看作是从“000000”到“111111”的变化的六位数,每一次变化采用逐位增的原则,将这64种变化遍历完之后,我们便讨论了所有的情况,由此可以得出是否有解的结论了。
2
3 int puzzle[6][8],press[6][8];
4
5 bool guess()
6 {
7 int c,r;
8 //首先调整第二行到第四行的等得亮灭情况,使其保持熄灭状态
9 for(r=1;r<5;r++)
10 {
11 for(c=1;c<7;c++)
12 {
13 press[r+1][c]=(puzzle[r][c]+press[r][c]+press[r-1][c]+press[r][c-1]+press[r][c+1])%2;
14 }
15 }
16 //最后我们来判断一下第五行的情况,这是我们唯一无法控制的,如果可以的话,我们就成功了
17 //否则,我们需要改变第一行的状态,进一步来寻找
18 for(c=1;c<7;c++)
19 {
20 if((press[5][c-1]+press[5][c]+press[5][c+1]+press[4][c])%2!=puzzle[5][c])
21 return false;
22 }
23 return true;
24 }
25
26 void enumate()
27 {
28 int c;
29 bool success;
30 for(c=1;c<7;c++)
31 //开始时,对于第一行的所有列都不按下按钮,试探一下
32 press[1][c]=0;
33 while(guess()==false)
34 {
35 //将第一行的所有2^6个状态一一遍历,这里还是缺乏容错性的,因为
36 //如果一直没有解的话,最后会因为数组越界而报错
37 press[1][1]++;
38 c=1;
39 while(press[1][c]>1)
40 {
41 press[1][c]=0;
42 c++;
43 press[1][c]++;
44 }
45 }
46 return;
47 }
48
49 int main()
50 {
51 int cases,i,r,c;//r,c代表行和列
52 scanf("%d",&cases);
53 //在三个方向上增加哨兵位
54 for(r=0;r<6;r++)
55 press[r][0]=press[r][7]=0;
56 for(c=1;c<7;c++)
57 press[0][c]=0;
58 //样例输入
59 for(i=0;i<cases;i++)
60 {
61 for(r=1;r<6;r++)
62 {
63 for(c=1;c<7;c++)
64 {
65 scanf("%d",&puzzle[r][c]);
66 }
67 }
68 enumate();//带搜索的枚举
69 //样例输出
70 printf("PUZZLE #%d\n",i+1);
71 for(r=1;r<6;r++)
72 {
73 for(c=1;c<7;c++)
74 {
75 printf("%d",press[r][c]);
76 }
77 printf("\n");
78 }
79 }
80 return 0;
81 }
82
83
浙公网安备 33010602011771号