1103 - Ancient Messages

In order tounderstand early civilizations, archaeologists often study texts written inancient languages. One such language, used in Egypt more than 3000 years ago,is based on characters called hieroglyphs. Figure C.1 shows six hieroglyphs andtheir names. In this problem, you will write a program to recognize these sixcharacters.

Figure C.1: Sixhieroglyphs

Input 

The input consistsof several test cases, each of which describes an image containing one or morehieroglyphs chosen from among those shown in Figure C.1. The image is given inthe form of a series of horizontal scan lines consisting of black pixels(represented by 1) and white pixels (represented by 0). In the input data, eachscan line is encoded in hexadecimal notation. For example, the sequence ofeight pixels 10011100 (one black pixel, followed by two white pixels,and so on) would be represented in hexadecimal notation as 9c. Only digitsand lowercase letters a through f are used in the hexadecimalencoding. The first line of each test case contains two integers, H and WH (0< H200) is the number ofscan lines in the image. W (0 < W50) is the number ofhexadecimal characters in each line. The next H lines containthe hexadecimal characters of the image, working from top to bottom. Inputimages conform to the following rules:

 

  • The image contains only hieroglyphs shown in Figure C.1.
  • Each image contains at least one valid hieroglyph.
  • Each black pixel in the image is part of a valid hieroglyph.
  • Each hieroglyph consists of a connected set of black pixels and each black pixel has at least one other black pixel on its top, bottom, left, or right side.
  • The hieroglyphs do not touch and no hieroglyph is inside another hieroglyph.
  • Two black pixels that touch diagonally will always have a common touching black pixel.
  • The hieroglyphs may be distorted but each has a shape that is topologically equivalent to one of the symbols in Figure C.1. (Two figures are topologically equivalent if each can be transformed into the other by stretching without tearing.)


The last test case is followed by a line containing two zeros.

Output 

For each testcase, display its case number followed by a string containing one character foreach hieroglyph recognized in the image, using the following code:


Ankh: A 
Wedjat: J 
Djed: D 
Scarab: S 
Was: W 
Akhet: K


In each output string, print the codes in alphabetic order. Follow the formatof the sample output.

The sample inputcontains descriptions of test cases shown in Figures C.2 and C.3. Due to spaceconstraints not all of the sample input can be shown on this page.


Sample Input 

100 25

0000000000000000000000000

0000000000000000000000000

...(50 linesomitted)...

00001fe0000000000007c0000

00003fe0000000000007c0000

...(44 linesomitted)...

0000000000000000000000000

0000000000000000000000000

150 38

00000000000000000000000000000000000000

00000000000000000000000000000000000000

...(75 linesomitted)...

0000000003fffffffffffffffff00000000000

0000000003fffffffffffffffff00000000000

...(69 lines omitted)...

00000000000000000000000000000000000000

00000000000000000000000000000000000000

0 0

Sample Output 

Case1: AKW

Case 2: AAAAA

代码:

#include

#include

#include

#include

#include

using namespacestd;

 

char bin[256][5];

 

const int maxh =200 + 5;

const int maxw =50 * 4 + 5;

 

int H, W,pic[maxh][maxw], color[maxh][maxw];

char line[maxw];

 

void decode(charch, int row, int col)

{

    for(int i = 0; i < 4; i++)

    {

        pic[row][col+i] = bin[ch][i] - '0';

    }

}

 

const int dr[] ={-1, 1, 0, 0};

const int dc[] ={0, 0, -1, 1};

 

void dfs(int row,int col, int c)

//功能:使每一片颜色相同的区域有一个相同的编号,不同的区域编号不同

{

    color[row][col] = c;

    for(int i = 0; i < 4; i++)//遍历周围”上下左右”四个区域

    {

        int row2 = row + dr[i];

        int col2 = col + dc[i];

        if(row2 >= 0 && row2 < H&& col2 >= 0 && col2 < W && pic[row2][col2] ==pic[row][col] && color[row2][col2] == 0)

//若越界或区域颜色不同或已经遍历过则退出

        {

            dfs(row2, col2, c);//递归深搜

        }

    }

}

 

vector> neighbors;

/*数组元素是集合的数组,每一个数组元素(集合)的大小代表相应的黑色连通块内的白洞个数*/

 

voidcheck_neighbors(int row, int col)

{

    for(int i = 0; i < 4; i++)

    {

        int row2 = row + dr[i];

        int col2 = col + dc[i];

        if(row2 >= 0 && row2 < H&& col2 >= 0&& col2 < W && pic[row2][col2] == 0&& color[row2][col2] != 1)

/*若越界或要查看的区域不是白色或区域是白色但是属于最外面的白色区域(最外面的白色区域编号必定为1,其余的白色区域,即白洞,编号必定不为1)*/

        {

           neighbors[color[row][col]].insert(color[row2][col2]);

//插入每一个白洞所特有的编号

        }

    }

}

 

const char* code ="WAKJSD";

 

char recognize(intc)//将白洞的个数转换成要输出的字符

{

    int cnt = neighbors[c].size();

    return code[cnt];

}

 

int main()

{

    strcpy(bin['0'], "0000");//bin字符数组用于解码

    strcpy(bin['1'], "0001");

    strcpy(bin['2'], "0010");

    strcpy(bin['3'], "0011");

    strcpy(bin['4'], "0100");

    strcpy(bin['5'], "0101");

    strcpy(bin['6'], "0110");

    strcpy(bin['7'], "0111");

    strcpy(bin['8'], "1000");

    strcpy(bin['9'], "1001");

    strcpy(bin['a'], "1010");

    strcpy(bin['b'], "1011");

    strcpy(bin['c'], "1100");

    strcpy(bin['d'], "1101");

    strcpy(bin['e'], "1110");

    strcpy(bin['f'], "1111");

 

    int kase = 0;

    while(scanf("%d%d", &H,&W) == 2 && H)

    {

        memset(pic, 0, sizeof(pic));

//pic数组用于存储解码后的图像,0为白色,1为黑色

        for(int i = 0; i < H; i++)

        {

            scanf("%s", line);

            for(int j = 0; j < W; j++)

            {

                decode(line[j], i+1, j*4+1);

/*解码函数:注意将输入的字符编码解码后存储的范围是

pic[1][1]       -------------------------------------------------------pic[1][4W]

---------------------------------------------------------------------------------

pic[H][1]-------------------------------------------------------pic[H][4W]

不要忘了:在四周多加了4条白边以使得白色区域能够连通*/

            }

        }

 

        H += 2;//多加了边

        W = W * 4 + 2;

 

        int cnt = 0;//编码序号

        vector cc; //存储黑色连通块的编码序号

       

        memset(color, 0, sizeof(color));//每次必须清空

        for(int i = 0; i < H; i++)

        {

            for(int j = 0; j < W; j++)

            {

                if(!color[i][j])//若未曾编号

                {

                    dfs(i, j, ++cnt);//深搜

                    if(pic[i][j] == 1)//表明搜的是:黑色连通块

                    {

                        cc.push_back(cnt);//存下黑色连通块的编号

                    }

                }

            }

        }

 

        neighbors.clear();//每组数据都要清空

        neighbors.resize(cnt+1);//设置大小

        for(int i = 0; i < H; i++)

        {

            for(int j = 0; j < W; j++)

            {

                if(pic[i][j] == 1)//求取黑色区域周围的白洞的个数

                {

                    check_neighbors(i, j);

                }

            }

        }

 

        vector ans;

        for(int i = 0; i < cc.size(); i++)

        {

            ans.push_back(recognize(cc[i]));

        }

        sort(ans.begin(), ans.end());//按字母顺序排列

 

        printf("Case %d: ", ++kase);

        for(int i = 0; i < ans.size(); i++)

        {

            printf("%c", ans[i]);

        }

        printf("\n");

    }

    return 0;

}

解析:

题意:

给出一幅黑白图像,每行相邻的四个点压缩成一个十六进制的字符。然后还有题中图示的6中古老的字符,按字母表顺序输出这些字符的标号。

分析:

首先图像是被压缩过的,所以我们要把它解码成一个01矩阵。而且我们还要在原图像的四周加一圈白边,这样图中的白色背景都连通起来了。黑色连通块的个数就是字符的个数。观察题中字符样式可知,每种字符中包裹的“白洞”的个数是不同的,所以我们可以根据每个字符中的“白洞”的个数来区别这些字符。然后我们给所有的连通块染色,并用color存储所标记的颜色。第一个染的是白色背景色,编号为1。把所有的黑色连通块的标号存放到cc里面neighbors是由若干个集合所组成的数组,记录的是黑色连通块i周围相连的非背景色的白块,即“白洞”。最后每个集合中元素的个数对应的就是字符的编号,最后排序输出即可。

 

示意图链接

你可能感兴趣的:(1103 - Ancient Messages)