首页 > 代码库 > UVa 1103 (利用连通块来判断字符) Ancient Messages

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 }
代码君

 

UVa 1103 (利用连通块来判断字符) Ancient Messages