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 }

浙公网安备 33010602011771号