POJ 2965

算法:枚举 + 深搜

每个把手翻转还是不翻转共两种情况,一共16个把手,即一共2的16次方种方法

方法:16个把手都决策好了(翻转还是不翻转)。

直接用二维数组x[i][j]记录即可,i代表每种情况的编号,j代表每种情况中每个把手的编号;而数组值为1代表翻转,为-1代表不翻转,

为0代表该把手的决策与上一种情况中的该把手的决策是相同的。

其实本题一维数组足够,且更为简便,当时没想太多。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 char s[5][5];
 5 int y[5][5], x[66000][17], ct[66000], o = 0, n = 0, mi = 65998;//用y[5][5]表示s[5][5],更新的时候容易更新,ct[66000]为每种方法的翻转次数,o为一开始开着的把手的数量,n为方法编号,mi为所求的那一种方法的编号。
 6 void shensou(int k, int op)//k表示把手编号,从左到右,从上到下,从0开始;op表示当前状态开着的把手的数量。
 7 {
 8     if(op == 16)//所有把手全部开着。
 9     {
10         if(ct[n] < ct[mi]) mi = n;//更新满足题意并且操作次数最少的方法编号。
11         for (int g = k; g < 16; g++) x[n][g] = -1;剩下的把手都不翻转。
12         n++;开始下一种方法。
13         return;
14     }
15     if(k == 16)
16     {
17         n++;
18         return;
19     }
20     int open = op, temp = ct[n], fx = k / 4, fy = k % 4;//fx和fy即把手的坐标。
21     for (int i = 0; i < 4; i++)//21 ~ 32行:更新同行同列把手状态。
22     {
23         y[i][fy] = !y[i][fy];
24         if(y[i][fy]) open++;
25         else open--;
26         y[fx][i] = !y[fx][i];
27         if(y[fx][i]) open++;
28         else open--;
29     }
30     y[fx][fy] = !y[fx][fy];
31     if(y[fx][fy]) open++;
32     else open--;
33     ct[n]++, x[n][k] = 1, shensou(k + 1, open);
34     ct[n] = temp, x[n][k] = -1;
35     for (int i = 0; i < 4; i++)
36     {
37         y[i][fy] = !y[i][fy];
38         y[fx][i] = !y[fx][i];
39     }
40     y[fx][fy] = !y[fx][fy];
41     shensou(k + 1, op);
42 }
43 int main()
44 {
45     for (int i = 0; i < 4; i++) scanf("%s", &s[i]);
46     for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) if(s[i][j] == '-') {o++, y[i][j] = 1;};
47     ct[mi] = 100, shensou(0, o);
48     printf("%d\n", ct[mi]);
49     for (int i = 15; i >= 0; i--)
50     {
51         while(x[mi][i] == 0) mi--;
52         if(x[mi][i] == 1) printf("%d %d\n", i / 4 + 1, i % 4 + 1);
53     }
54 }

 

posted @ 2018-03-26 18:23  ConstVariable  阅读(227)  评论(0)    收藏  举报