UVA1103 Ancient Messages 题解

古代象形符号

每组数据包含一个H行W列的字符矩阵(H≤200,W≤50),每个字符为4个相邻像素点的十六进制(例如,10011100对应的字就是9c)。转化为二进制后1表示黑点,0表示白点。输入满足:

- 不会出现上述6种符号之外的其他符号。

- 输入至少包含一个符号,且每个黑像素都属于一个符号。

- 每个符号都是一个四连块,并且不同符号不会相互接触,也不会相互包含。

- 如果两个黑像素有公共顶点,则它们一定有一个相同的相邻黑像素(有公共边)。

- 符号的形状一定和表中的图形拓扑等价(可以随意拉伸但不能拉断)。

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

要求按照字典序输出所有符号。

思路:表中6个符号从左至右依次有1(A),3(J),5(D),4(S),0(W),2(K)个圈,各不相同。所以判断圈的个数即可。

以下列数据演示:

10 3
000
778
548
748
578
700
000
7f0
1e0
000
初始图

实现方法:

1. 黑色块包裹的圈内白色块肯定不会四连块连接到边缘的块去,所以遍历4条边,并且标记这些非圈内白块。(如图)

图1

2. 开始遍历找黑块,找到一个后进入dfs标记连通块,由题意,一个黑色块最终能标记一整个符号。

继续找黑色块,如果还有,那就是第二个符号,依次类推,同时给符号的标记做区分处理,顺便记录符号个数。

图2

3. 找白色块,此时找到的都是圈内的,找到第一个就dfs标记所有该圈内的白色块(用-2)。

此时判断白色块属于哪个符号:如第一个白色块坐标为(x,y),那么(x-1,y)肯定是黑色块,因为经过了这个黑色块才能进圈。

图3

4. 字典序输出结果。

#include <bits/stdc++.h>
using namespace std;
int pic[200][200], ascii[6]={87,65,75,74,83,68},H, W,n = 0,
    t[16][4] = {{0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}, {0, 0, 1, 1},
                {0, 1, 0, 0}, {0, 1, 0, 1}, {0, 1, 1, 0}, {0, 1, 1, 1},
                {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 0, 1, 0}, {1, 0, 1, 1},
                {1, 1, 0, 0}, {1, 1, 0, 1}, {1, 1, 1, 0}, {1, 1, 1, 1}};
void filled()//输入图
{
    char temp;
    for (int i = 0; i < H; i++)
        for (int k = 0, c = 0; k < W; k++)
        {
            scanf(" %c", &temp); //空格吸收回车,字符串读入
            if (temp > 96)  temp -= 87; //97为a
            else            temp -= 48;
            for (int f = 0; f < 4; f++)   //输入的转为4个二进制
                pic[i][c++] = t[temp][f]; //c为当前行第几个,换行时清零
        }
}
void dfs(int y, int x, int f, int a) //y行 x列 f需要标记的值  a要连通的格子类型
{
    if (x >= 4 * W || x < 0 || y >= H || y < 0 || pic[y][x] != a) return; //出界OR不是要爬的格子
    pic[y][x] = f; //标记当前格为f
    dfs(y - 1, x, f, a);
    dfs(y + 1, x, f, a);
    dfs(y, x - 1, f, a);
    dfs(y, x + 1, f, a);
}
int main()
{
    while (cin >> H >> W) //H行 W列
    {
        if (H == 0)
            break; //结束条件0 0
        filled();
        cout << "Case " << ++n << ": ";
        int n = 4, c[100] = {0},cnt=0;    //c数组存放符号n的圈的个数
        for (int i = 0; i < H; i++) //功能:遍历四条边的每一点
        {
            int q = 4 * W;
            if (i == 0 || i == H - 1) q = 2;
            for (int j = 0; j < 4 * W; j += q - 1)
                dfs(i, j, -1, 0);
        }
        for (int i = 0; i < H; i++) //功能:标记每个黑块组成的符号
            for (int j = 0; j < 4 * W; j++)
                if (pic[i][j] == 1)
                    dfs(i, j, n++, 1); //防止混淆,n初始为4,当前符号标记为4
        for (int i = 0; i < H; i++) //功能:找白块
            for (int j = 0; j < 4 * W; j++)
                if (pic[i][j] == 0)
                {
                    c[pic[i][j - 1]]++; //直接找前一个黑块的值作为该符号的号码,表示增加一个圈
                    dfs(i, j, -2, 0);   //用-2标记已经计算过的圈内白块
                }
        for (int i = 4; i < n; i++) c[i]=ascii[c[i]]; //将值换成ASCII码存放
        sort(c+4,c+n);//对c数组第4个到第n-1个升序排序
        for (int i = 4; i < n; i++) printf("%c",c[i]); //字典序输出 n初始是从4开始算
        cout << endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/linme/p/11978278.html
今日推荐