Fliptile POJ-3279 DFS
题目链接:Fliptile
题目大意
有一个01矩阵,每一次翻转(0->1或者1->0)一个元素,就会把与他相邻的四个元素也一起翻转。求翻转哪些元素能用最少的步骤,把矩阵变成0矩阵。
思路
假设确定了第一行的状态,那么第二行需要翻转的所有元素都能确定(上一行如果是1就必须翻转)。因此对于所有第一排的情况,往下递推需要翻转的元素,最后判断最后一行如果全为0则满足条件,记录步骤最少的情况。
题解
1 #include <iostream> 2 #include <cstring> 3 4 using namespace std; 5 6 int n, m, mmin=0x3f3f3f3f; 7 int map[20][20],tmp[20][20],ans[20][20]; 8 9 bool judge(){ 10 for(int i = 0 ; i < m; i++) 11 { 12 int time = tmp[n-2][i] + tmp[n-1][i]; 13 if(i != 0) 14 { 15 time += tmp[n-1][i-1]; 16 } 17 if(i != m-1) 18 { 19 time += tmp[n-1][i+1]; 20 } 21 time %= 2; 22 if(map[n-1][i] ^ time){ 23 return false; 24 } 25 } 26 return true; 27 } 28 29 void dfs(int k, int num) 30 { 31 if(num > mmin) return; 32 if(k > n-1) //最后一行遍历 结束,判断最后一行是否全0 33 { 34 if(judge() && num < mmin) 35 { 36 memcpy(ans, tmp, sizeof(tmp)); 37 mmin = num; 38 } 39 return; 40 } 41 int flag = 0; 42 43 for(int i = 0; i < m; i++) 44 { 45 int time = 0; 46 time = tmp[k-1][i] + tmp[k-2][i]; 47 if(i != 0) 48 { 49 time += tmp[k-1][i-1]; 50 } 51 if(i != m-1) 52 { 53 time += tmp[k-1][i+1]; 54 } 55 if((map[k-1][i]+time)&1) 56 { 57 tmp[k][i] = 1; 58 flag++; 59 } 60 else 61 { 62 tmp[k][i] = 0; 63 } 64 } 65 dfs(k+1, num+flag); //搜索下一行 66 } 67 68 void todfs(int k, int num) 69 { 70 if(k > m - 1){ //遍历完第一行 71 dfs(1, num); //从第二行开始 72 return; 73 } 74 tmp[0][k] = 0; 75 todfs(k+1, num); 76 tmp[0][k] = 1; 77 todfs(k+1, num+1); 78 } 79 80 int main(int argc, char const *argv[]) 81 { 82 #ifdef debug 83 freopen("test.txt","r",stdin); 84 #endif 85 cin >> n >> m; 86 for(int i = 0; i < n; i++) 87 { 88 for (int j = 0; j < m; j++) 89 { 90 cin >> map[i][j]; 91 } 92 } 93 todfs(0, 0); 94 if(mmin == 0x3f3f3f3f) 95 { 96 cout << "IMPOSSIBLE" << endl; 97 } 98 else 99 { 100 for(int i = 0; i < n; i++) 101 { 102 for(int j = 0; j < m; j++) 103 { 104 cout << ans[i][j] << " "; 105 } 106 cout << endl; 107 } 108 } 109 return 0; 110 }
其实这个题用的数组下标最好是从1开始,这样不用把列号是0的元素拿出来单独计算了。