UVa 1103 (利用连通块来判断字符) Ancient Messages
本题就是灵活运用DFS来求连通块来求解的。
题意:
给出一幅黑白图像,每行相邻的四个点压缩成一个十六进制的字符。然后还有题中图示的6中古老的字符,按字母表顺序输出这些字符的标号。
分析:
首先图像是被压缩过的,所以我们要把它解码成一个01矩阵。而且我们还要在原图像的四周加一圈白边,这样图中的白色背景都连通起来了。
黑色连通块的个数就是字符的个数。
观察题中字符样式可知,每种字符中包裹的“白洞”的个数是不同的,所以我们可以根据每个字符中的“白洞”的个数来区别这些字符。
然后我们给所有的连通块染色,并用color存储所标记的颜色。第一个染的是白色背景色,编号为1
把所有的黑色连通块的标号存放到cc里面
neighbors是由若干个集合所组成的数组,记录的是黑色连通块i周围相连的非背景色的白块,即“白洞”。
最后每个集合中元素的个数对应的就是字符的编号,最后排序输出即可。
一个DEBUG很久的低级错误:在DFS的时候忘了加 color[row2][col2] == 0 这一判断条件,相当于没有回溯了,当然会栈溢出,RE。这里的color顺带也起到了表示是否访问过的作用。
1 //#define LOCAL 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <vector> 6 #include <set> 7 using namespace std; 8 9 const int maxl = 200 + 5; 10 char bin[256][5], s[maxl]; 11 const int dr[] = { 1, 0, -1, 0 }; 12 const int dc[] = { 0, 1, 0, -1 }; 13 int picture[maxl][maxl], color[maxl][maxl], w, h; 14 15 vector<set<int> > neighbor; 16 17 void decode(int row, int col, char c) 18 { 19 for(int i = 0; i < 4; ++i) 20 picture[row][col + i] = bin[c][i] - '0'; 21 } 22 23 bool inside(int row, int col) 24 { 25 return row>=0 && row<h && col>=0 && col<w; 26 } 27 28 void DFS(int row, int col, int c) 29 { 30 color[row][col] = c; 31 for(int i = 0; i < 4; ++i) 32 { 33 int row2 = row + dr[i]; 34 int col2 = col + dc[i]; 35 if(inside(row2, col2) && picture[row][col] == picture[row2][col2] && color[row2][col2] == 0) 36 DFS(row2, col2, c); 37 } 38 } 39 40 void check_neighbor(int row, int col) 41 { 42 for(int i = 0; i < 4; ++i) 43 { 44 int row2 = row + dr[i]; 45 int col2 = col + dc[i]; 46 if(row2>=0 && row2<h && col2>=0 && col2<w && picture[row2][col2] == 0 && color[row2][col2] != 1)//寻找"洞" 47 neighbor[color[row][col]].insert(color[row2][col2]); 48 } 49 } 50 51 const char* code = "WAKJSD"; 52 53 char recgonize(int c) 54 { 55 int a = neighbor[c].size(); 56 return code[a]; 57 } 58 59 int main(void) 60 { 61 #ifdef LOCAL 62 freopen("1103in.txt", "r", stdin); 63 #endif 64 65 strcpy(bin['0'], "0000"); 66 strcpy(bin['1'], "0001"); 67 strcpy(bin['2'], "0010"); 68 strcpy(bin['3'], "0011"); 69 strcpy(bin['4'], "0100"); 70 strcpy(bin['5'], "0101"); 71 strcpy(bin['6'], "0110"); 72 strcpy(bin['7'], "0111"); 73 strcpy(bin['8'], "1000"); 74 strcpy(bin['9'], "1001"); 75 strcpy(bin['a'], "1010"); 76 strcpy(bin['b'], "1011"); 77 strcpy(bin['c'], "1100"); 78 strcpy(bin['d'], "1101"); 79 strcpy(bin['e'], "1110"); 80 strcpy(bin['f'], "1111"); 81 82 int kase = 0; 83 while(scanf("%d%d", &h, &w) == 2 && h) 84 { 85 memset(picture, 0, sizeof(picture)); 86 for(int i = 0; i < h; ++i) 87 { 88 scanf("%s", s); 89 for(int j = 0; j < w; ++j) 90 decode(i+1, j*4+1, s[j]); 91 } 92 93 h += 2; 94 w = w * 4 + 2; 95 96 int cnt = 0; 97 vector<int> cc; 98 memset(color, 0, sizeof(color)); 99 for(int i = 0; i < h; ++i) 100 for(int j = 0; j < w; ++j) 101 if(!color[i][j]) 102 { 103 DFS(i, j, ++cnt); 104 if(picture[i][j] == 1) cc.push_back(cnt); 105 } 106 107 neighbor.clear(); 108 neighbor.resize(cnt + 1); 109 for(int i = 0; i < h; ++i) 110 for(int j = 0; j < w; ++j) 111 if(picture[i][j] == 1) 112 check_neighbor(i, j); 113 114 vector<char> ans; 115 for(int i = 0; i < cc.size(); ++i) 116 ans.push_back(recgonize(cc[i])); 117 sort(ans.begin(), ans.end()); 118 119 printf("Case %d: ", ++kase); 120 for(int i = 0; i < ans.size(); ++i) printf("%c", ans[i]); 121 printf("\n"); 122 } 123 124 return 0; 125 }