• Uva1103 古代象形符号


    题目描述:题目很长,就贴一下题目连接吧=_=。。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 << "
    ";
     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 << "
    ";
     31     static int n = 1;
     32     //cout << 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()) == '
    ');
     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 << "
    ";
     96         ans.clear();
     97     }
     98     
     99 
    100 }

    PS: 看了作者的实现代码,也将其记录下来,学习~

    其主要思路是用dfs给各个联通块涂上不同颜色,将是象形文字的联通块单独保存,再对原图像的每个像素,检查其四周的邻居,neighbors[color]<set>就保存各个颜色联通块与周围哪些颜色块相邻。最后看单独保存的象形文字联通块的neighbors的大小,就可以得到其内部有多少“空洞”。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #include<vector>
      5 #include<set>
      6 using namespace std;
      7 
      8 char bin[256][5];
      9 
     10 const int maxh = 200 + 5;
     11 const int maxw = 50 * 4 + 5;
     12 
     13 int H, W, pic[maxh][maxw], color[maxh][maxw];
     14 char line[maxw];
     15 
     16 void decode(char ch, int row, int col) {
     17   for(int i = 0; i < 4; i++)
     18     pic[row][col+i] = bin[ch][i] - '0';
     19 }
     20 
     21 const int dr[] = {-1, 1, 0, 0};
     22 const int dc[] = {0, 0, -1, 1};
     23 
     24 // dfs from (row, col) and paint color c
     25 void dfs(int row, int col, int c) {
     26   color[row][col] = c;
     27   for(int i = 0; i < 4; i++) {
     28     int row2 = row + dr[i];
     29     int col2 = col + dc[i];
     30     if(row2 >= 0 && row2 < H && col2 >= 0 && col2 < W && pic[row2][col2] == pic[row][col] && color[row2][col2] == 0) //下一步在范围内&&是相同性质联通块(白色块or象形文字)&&未被访问
     31       dfs(row2, col2, c);                                                              
     32   }
     33 }
     34 
     35 vector<set<int> > neighbors;
     36 
     37 void check_neighbors(int row, int col) {
     38   for(int i = 0; i < 4; i++) {
     39     int row2 = row + dr[i];
     40     int col2 = col + dc[i];
     41     if(row2 >= 0 && row2 < H && col2 >= 0&& col2 < W && pic[row2][col2] == 0 && color[row2][col2] != 1)//相邻像素块 在范围内&&性质是白色联通块&&该白色联通块不是整个背景
     42       neighbors[color[row][col]].insert(color[row2][col2]);
     43   }
     44 }
     45 
     46 const char* code = "WAKJSD";
     47 
     48 char recognize(int c) {
     49   int cnt = neighbors[c].size();
     50   return code[cnt];
     51 }
     52 
     53 // use this function to print the decoded picture
     54 void print() {
     55   for(int i = 0; i < H; i++) {
     56     for(int j = 0; j < W; j++) printf("%d", pic[i][j]);
     57     printf("
    ");
     58   }
     59 }
     60 
     61 int main() {
     62   strcpy(bin['0'], "0000");
     63   strcpy(bin['1'], "0001");
     64   strcpy(bin['2'], "0010");
     65   strcpy(bin['3'], "0011");
     66   strcpy(bin['4'], "0100");
     67   strcpy(bin['5'], "0101");
     68   strcpy(bin['6'], "0110");
     69   strcpy(bin['7'], "0111");
     70   strcpy(bin['8'], "1000");
     71   strcpy(bin['9'], "1001");
     72   strcpy(bin['a'], "1010");
     73   strcpy(bin['b'], "1011");
     74   strcpy(bin['c'], "1100");
     75   strcpy(bin['d'], "1101");
     76   strcpy(bin['e'], "1110");
     77   strcpy(bin['f'], "1111");
     78 
     79   int kase = 0;
     80   while(scanf("%d%d", &H, &W) == 2 && H) {
     81     memset(pic, 0, sizeof(pic));
     82     for(int i = 0; i < H; i++) {
     83       scanf("%s", line);
     84       for(int j = 0; j < W; j++)
     85         decode(line[j], i+1, j*4+1);
     86     }
     87 
     88     H += 2;
     89     W = W * 4 + 2;
     90 
     91     int cnt = 0;
     92     vector<int> cc; // connected components of 1
     93     memset(color, 0, sizeof(color));
     94     for(int i = 0; i < H; i++)
     95       for(int j = 0; j < W; j++)
     96         if(!color[i][j]) {
     97           dfs(i, j, ++cnt);
     98           if(pic[i][j] == 1) cc.push_back(cnt);
     99         }
    100 
    101     neighbors.clear();
    102     neighbors.resize(cnt+1);
    103     for(int i = 0; i < H; i++)
    104       for(int j = 0; j < W; j++)
    105         if(pic[i][j] == 1)
    106           check_neighbors(i, j);
    107 
    108     vector<char> ans;
    109     for(int i = 0; i < cc.size(); i++)
    110       ans.push_back(recognize(cc[i]));
    111     sort(ans.begin(), ans.end());
    112 
    113     printf("Case %d: ", ++kase);
    114     for(int i = 0; i < ans.size(); i++) printf("%c", ans[i]);
    115     printf("
    ");
    116   }
    117   return 0;
    118 }
  • 相关阅读:
    添加常驻Notification
    Java 数组操作
    一百本英文原著之旅 ( 15 finished )
    SQLServer2005中查询语句的执行顺序
    高效程序员的45个习惯
    博客园经典闪存语录
    for xml path('') 引发的数据不完整
    ajax向前台输出二维数组 并解析
    重视知识的本质
    C语言排序
  • 原文地址:https://www.cnblogs.com/patrolli/p/11273158.html
Copyright © 2020-2023  润新知