题目链接: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 }
View Code

我想说这个题在毫无思路的情况下,被小王sir告知思路,然后,尝试代码实现写出来的。感觉自己好厉害【傲娇脸】。第一行的枚举用十进制数的二进制形式表示。记录最终答案的过程。啊哈。以上。

 

posted on 2016-01-18 13:48  小小八  阅读(216)  评论(0编辑  收藏  举报