题目链接:http://poj.org/problem?id=3279
大意:给出一块n*m的棋盘。里面放满了棋子。有1和0两种状态。给出初始状态,翻动的时候会把当前位置和当前位置的上下左右共五个位置翻动。现在问最小步骤的翻动方案。步 骤数相同时按照字典序输出。(输出按照n*m的形式输出每个格子的翻动次数)
其中!字典序的意思是每行首尾相接连成的字符串排序。亲测和顺序有关。
改了字典序之后,测试无数次找到神奇的bug就是string字符串的初始化。2333。
其实感觉不是dfs,至少对我来说就是一个二进制枚举+search的过程。不如说是暴力search?
附代码,已AC。
1 // 我想说我不会这个题。开始的时候是感觉每个格子搜一遍的超暴力dfs 我是可以的。然后呢。一定会超时的。恩。 2 // 然后先确定第一行的操作就可以确定第二行的操作了?恩。因为我第二行肩负着让第一行全部为0的使命。 3 // 不能随便动、必须和第一行完全对应。依次类推。知道最后一行都是确定的。然后、 4 // 如果最后一行的操作同时使最后一行全部变成0了。就是可行方案。否则不是。 5 // QAQ。然而纠结了半天新的问题是怎么代码实现呢。恩。第一行的操作遍历可以抽象成一个10进制数0到(2^n-1)的变换、 6 // 然后每次都按行搜索下去。好了。具体的看代码吧。。QAQ、 7 8 #include <stdio.h> 9 #include <string.h> 10 #include <iostream> 11 #define maxn 10000010 12 #include <algorithm> 13 using namespace std; 14 15 int m, n; 16 int mp[20][20]; 17 int num[20][20]; 18 int ans; 19 int mpcpy[20][20]; 20 int cnt; 21 22 int dir[5][2] = {1, 0, -1, 0, 0, 1, 0, -1, 0, 0}; 23 int ansnum[20][20]; 24 string ans2[1000]; 25 26 int pow(int n) { 27 int temp = 1; 28 for (int i=0; i<n; ++i) { 29 temp *= 2; 30 } 31 return temp; 32 } 33 34 bool check(int x, int y) { 35 if (x >=0 && x < m && y >= 0 && y < n) 36 return true; 37 return false; 38 } 39 40 void filp(int ii, int jj) { 41 for (int i=0; i<5; ++i) { 42 int x = ii + dir[i][0]; 43 int y = jj + dir[i][1]; 44 if (check(x, y)) 45 mpcpy[x][y] = 1 - mpcpy[x][y]; 46 } 47 } 48 49 int min(int a, int b) { 50 if (a < b) return a; 51 else return b; 52 } 53 54 int dfs() { 55 int tempans = 0; 56 for (int i=0; i<m; ++i) { 57 for (int j=0; j<n; ++j) { 58 mpcpy[i][j] = mp[i][j]; 59 } 60 } 61 62 for (int i=0; i<n; ++i) { 63 if (num[0][i] == 1) { 64 tempans++; 65 filp(0, i); 66 } 67 } 68 69 for (int i=0; i<m-1; ++i) { 70 for (int j=0; j<n; ++j) { 71 if (mpcpy[i][j] == 1) { 72 tempans++; 73 num[i+1][j] = 1; 74 filp(i+1, j); 75 } 76 } 77 } 78 79 for (int i=0; i<m; ++i) { 80 for (int j=0; j<n; ++j) 81 if (mpcpy[i][j] == 1) 82 return maxn; 83 } 84 return tempans; 85 } 86 87 int main() { 88 while(cin >> m >> n) { 89 for (int i=0; i<m; ++i) { 90 for (int j=0; j<n; ++j) { 91 cin >> mp[i][j]; 92 } 93 } 94 int temp = 0; 95 int tempmax = pow(n+1) - 1; 96 ans = maxn; 97 cnt = 0; 98 while(temp < tempmax) { 99 memset(num, 0, sizeof(num)); 100 string anstemp = ""; 101 int temp2 = temp; 102 for (int i=0; i<n; ++i) { 103 num[0][i] = temp2 % 2; 104 temp2 /= 2; 105 } 106 temp++; 107 108 if (ans > dfs()) { 109 ans = dfs(); 110 for (int i=0; i<m; ++i) { 111 for (int j=0; j<n; ++j) { 112 anstemp += '0' + num[i][j]; 113 } 114 } 115 ans2[cnt++] = anstemp; 116 } 117 } 118 119 if (ans == maxn) { 120 cout << "IMPOSSIBLE\n"; 121 continue; 122 } 123 sort(ans2, ans2+cnt); 124 int tt = 0; 125 for (int i=0; i<m; ++i) { 126 for (int j=0; j<n; ++j) { 127 if (j == 0) cout << ans2[0][tt++]; 128 else cout << ' ' << ans2[0][tt++]; 129 } 130 cout << endl; 131 } 132 } 133 return 0; 134 }
我想说这个题在毫无思路的情况下,被小王sir告知思路,然后,尝试代码实现写出来的。感觉自己好厉害【傲娇脸】。第一行的枚举用十进制数的二进制形式表示。记录最终答案的过程。啊哈。以上。