题目描述:题目很长,就贴一下题目连接吧=_=。。https://vjudge.net/problem/UVA-1103
大意是输入一个H行W列的字符矩阵(H<=200, W<=50)。每个字符为4个相邻像素点的十六进制(即10011100对应的是9c),这样可以得到一副图片,然后找出图片中包含的题目中给出的六种象形符号是哪些。
思路:这是紫书上的一个例题,作者给出了一个重要的提示,即找这几个象形符号的特征在每个符号内部的空白数不同,我们只要找出每个黑色联通块内部有几个空白,就能知道这个黑色联通块对应哪个符号,找联通块用dfs即可。按照这个思路,我的做法是将每个黑色联通块都从原始图像中提取出来,其背景为白色,这样数有多少个白色联通块,就能确定是哪个符号。最后花了很长时间才把程序调试出来,有几个细节没有注意,比如需要对原始图片上下左右各添加一列空白,这样可以避免在边界时出现多将空白判定为黑色联通块内部的情况。
代码如下:
1 #include <iostream> 2 #include <memory.h> 3 #include <string> 4 #include <algorithm> 5 using namespace std; 6 const int maxn = 206; 7 int pix[maxn][maxn]; 8 int idx[maxn][maxn]; 9 int mcopy[maxn][maxn][maxn]; //mcopy[i][][]表示将第i个象形文字提取出来后得到的图片 10 int H, W; 11 const char code[6] = {'W', 'A', 'K', 'J', 'S', 'D'}; 12 13 void dfs(int r, int c, int id, int symbol) //这是对原始图片dfs的函数,用来找黑色联通块,以及提取每个黑色联通块到mcopy中 14 { 15 if(r < 0 || r > H+1 || c < 0 || c > W*4+1) return; 16 if(idx[r][c] > 0 || pix[r][c] != symbol) return; 17 18 19 // cout << "r: " << r << " c: " << c << "\n"; 20 idx[r][c] = id; 21 mcopy[id-1][r][c] = 1; 22 dfs(r-1, c, id, symbol); 23 dfs(r+1, c, id, symbol); 24 dfs(r, c-1, id, symbol); 25 dfs(r, c+1, id, symbol); 26 } 27 28 void dfs(int r, int c, int id, int symbol, int i) //这是对mcopy处理的函数,找其中白色联通块的个数 29 { 30 //cout << "r: " << r << "c: " << c << "\n"; 31 static int n = 1; 32 //cout << n++ << "\n"; 33 if(r < 0 || r > H+1 || c < 0 || c > W*4+1) return; 34 if(idx[r][c] > 0 || mcopy[i][r][c] != 0) return; 35 idx[r][c] = id; 36 dfs(r-1, c, id, symbol, i); 37 dfs(r+1, c, id, symbol, i); 38 dfs(r, c-1, id, symbol, i); 39 dfs(r, c+1, id, symbol, i); 40 } 41 42 int chartonum(char c) 43 { 44 if(isalpha(c)) return c-'a'+10; 45 else return c-'0'; 46 } 47 48 int main() 49 { 50 //freopen("uva1103_in.txt", "r", stdin); 51 //freopen("uva1103_out.txt", "w", stdout); 52 int kase = 0; 53 char c; 54 55 while(cin >> H >> W && H){ 56 memset(pix, 0, sizeof(pix)); //之前这里清零的位置放在了while外面,导致wa。每处理一个新的图片都要将此前的图片清零 57 int val, y = 1; 58 for(int i = 1; i <= H; ++i){ //输入处理操作 59 y = 1; 60 for(int j = 0; j < W; ++j){ 61 while((c = getchar()) == '\n'); 62 val = chartonum(c); 63 for(int x = 0; x < 4; ++x){ 64 pix[i][y] = (val & 0x08) >> 3; 65 y = (y+1) % (4*W+1); 66 val = val << 1; 67 } 68 } 69 } 70 memset(idx, 0, sizeof(idx)); 71 memset(mcopy, 0, sizeof(mcopy)); 72 int cnt = 0; 73 for(int i = 0; i < H+2; ++i){ //对原始图像进行处理,cnt是原始图像中象形文字的个数 74 for(int j = 0; j < W*4+2; ++j){ 75 if(idx[i][j] == 0 && pix[i][j] == 1){ 76 dfs(i, j, ++cnt, 1); 77 } 78 } 79 } 80 printf("Case %d: ", ++kase); 81 string ans; 82 for(int i = 0; i < cnt; ++i){ //对每个象形文字 83 memset(idx, 0, sizeof(idx)); //访问状态数组idx清零 84 int num = 0; 85 for(int j = 0; j < H+2; ++j){ 86 for(int k = 0; k < W*4+2; ++k){ 87 if(idx[j][k] == 0 && mcopy[i][j][k] == 0){ //数有几个白块 88 dfs(j, k, ++num, 0, i); //如果(j,k)位置没有被访问 && (j,k)上是一个空白像素点, 从它开始dfs, 找到一个联通块 89 } 90 } 91 } 92 ans += code[num-1]; //num是白色联通块的个数,这样就能对应出是哪一个象形文字,加入ans中 93 } 94 sort(ans.begin(),ans.end()); //按字母大小序排列 95 cout << ans << "\n"; 96 ans.clear(); 97 } 98 99 100 }
PS: 看了作者的实现代码,也将其记录下来,学习~