Uva 1103古代象形符号

题目描述:题目很长,就贴一下题目连接吧=_=。。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: 看了作者的实现代码,也将其记录下来,学习~

猜你喜欢

转载自www.cnblogs.com/patrolli/p/11273158.html