原题:
UVA 1103
洛谷 古代象形符号

问题描述

问题输入输出

输入

输出

输入输出样例

Input:
6 2
00
7c
44
7c
30
00
6 25
0000000000000000000000000
0000000000000000000000000
00001fe0000000000007c0000
00003fe0000000000007c0000
0000000000000000000000000
0000000000000000000000000
10 3
000
778
548
748
578
700
000
7f0
1e0
000
16 2
00
7e
42
7e
42
7e
42
7e
42
7e
42
7e
00
00
4a
00
16 1
0
1
3
2
8
e
f
5
7
6
4
c
d
9
b
a
9 2
00
7e
42
7e
42
7e
42
7e
00Output:
Case 1: A
Case 2: WW
Case 3: AKW
Case 4: DWWW
Case 5: AWW
Case 6: J

题目大意

  • 输入一个高、宽为h、w的字符矩阵,一个字符表示一个16进制数,来表示输入的图像
  • 每个图像至少包含一个象形文字
  • 象形文字之间不接触、不包含
  • 象形文字可能会被拉伸,但是拓扑结构上是等效的
  • 象形文字是“四连通的”,即一个象形文字的黑色元素至少有一个上、下、左或者右是其他黑色元素。

题目分析

  • 对于每种象形文字,我们应该需要找到其独有的“特征向量”,通过观察,我们发现象形文字内部的空洞(白洞)数目是不同的,分别对应于A=1; J=3; D=5; S=4; W=0; K=2
  • 所以我们可以使用DFS深度优先遍历来数象形文字内部的空洞数目,以此来判断是哪种象形文字。

但是我们会遇到以下问题:

  • 怎么将输入的16进制数,转成2进制数,进而转换成图像种的0/1矩阵?
    16进制数用4位二进制数来表示,我们可以每次向右移动一位取出4为二进制数字。或者提前写好16个数对应的二进制数表示。
  • 怎么数象形文字内部的空洞数目?
    • 先用DFS扣除外部背景图像(由四周向中间的背景都要抠出来)
    • 然后对每个象形文字进行一次DFS,若在DFS时遇到内部空洞,则对空洞进行一次DFS并计数
    • 最后返回统计的空洞数目
/* Ancient Messages */
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<queue>
#include<functional>
using namespace std;
//#define DEBUGconst int maxh = 210;
const int maxw = 60;
const int width = 4; // 一个字符对应的像素数量
int h, w;
char line[maxw]; // 对应于输入的一行字符
int image[maxh][maxw * width];char word[6] = { 'W','A','K','J','S','D' }; // 各个空洞对应的象形文字
int mov[4][2] = { {0,1},{0,-1},{1,0},{-1,0} }; // 移动的4个方向void printMap() { // 打印填充后的图形for (int i = 0; i < h; i++) {for (int j = 0; j < 4 * w; j++) printf("%d", image[i][j]);printf("\n");}
}
int isRight(int x, int y) {// 该位置是否在图内if (x < 0 || x >= h || y < 0 || y >= width * w) return 0;return 1;
}
int char2int(char c) {if (c >= '0' && c <= '9') return c - '0';else return c - 'a' + 10;
}
void dfs_background(int x, int y, int val) {// 填充背景,填充值为val,默认为-1image[x][y] = val;for (int i = 0; i < 4; i++) {int nx = x + mov[i][0];int ny = y + mov[i][1]; // 下一次移动的位置if (isRight(nx, ny) && image[nx][ny] == 0) dfs_background(nx, ny, val); // 没遍历过的背景}
}
void dfs_word(int x, int y, int& cnt) {//printf("遍历汉字,位置(%d,%d)\n", x, y);image[x][y] = -1; // 暂时标记成背景,也可以标记成其他元素,比如文字对应的idfor (int i = 0; i < 4; i++) {int nx = x + mov[i][0];int ny = y + mov[i][1]; // 下一次移动的位置if (isRight(nx, ny) && image[nx][ny] == 1) dfs_word(nx, ny, cnt);else if (isRight(nx, ny) && image[nx][ny] == 0) {// 内部空洞cnt++;dfs_background(nx, ny, -1);}}
}
int main() {int kcase = 1;while (cin >> h >> w && h) {priority_queue<char, vector<char>, greater<char> > ans; // 答案memset(image, 0, sizeof(image));for (int i = 0; i < h; i++) {scanf("%s", line);for (int j = 1; j <= w; j++) { // 将line转换成二进制存储int num = char2int(line[j-1]);for (int k = 4 * j - 1; k >= 4 * j - 4; k--) { // 第j个字符对应的二进制image[i][k] = (num & 1); // 取出最低位num >>= 1; // 右移一位}}}// 输入完毕
#ifdef DEBUGprintf("输入的图像\n");printMap();
#endif/*** 这里需要注意一个问题,扣背景的时候需要从4周开始从外向内扣** 因为有些文字可能与边缘接触,导致从(0,0)起点开始扣覆盖面不全*/for (int i = 0; i < h; i++) {if (image[i][0] == 0) dfs_background(i, 0,-1);if (image[i][4 * w - 1] == 0) dfs_background(i, 4 * w - 1,-1);}for (int i = 0; i < 4 * w; i++) {if (image[0][i] == 0) dfs_background(0, i, -1);if (image[h - 1][i] == 0) dfs_background(h - 1, i, -1);}
#ifdef DEBUGprintf("背景填充后\n");printMap();
#endiffor (int i = 0; i < h; i++) {for (int j = 0; j < width * w; j++) {if (image[i][j] == 1) {// 表示一个文字int cnt = 0; // 空洞数目dfs_word(i, j, cnt);ans.push(word[cnt]);}}}// 遍历完成printf("Case %d: ", kcase); kcase++;while (ans.size()) {char c = ans.top(); ans.pop();printf("%c", c);}printf("\n");}return 0;
}

(UVA 1103) Ancient Meesages(DFS连通分量计数+种子填充floodfill算法)相关推荐

  1. UVA 1103 - Ancient Messages(古代象形符号) By SuCicada

    本题的目的是识别3000年前古埃及用到的6种象形文字,如图6-10所示. 图6-10 古代象形符号 每组数据包含一个H行W列的字符矩阵(H≤200,W≤50),每个字符为4个相邻像素点的 十六进制(例 ...

  2. Uva 1103 Ancient Messages

    大致思路是DFS: 1. 每个图案所包含的白色连通块数量不一: Ankh : 1 ;  Wedjat : 3  ; Djed : 5   ;   Scarab : 4 ; Was : 0  ;  Ak ...

  3. 例题6-13 古代象形符号(Ancient Messages,World Finals 2011,UVa 1103)

    原题链接:https://vjudge.net/problem/UVA-1103 分类:图 备注:思维 前言:说实话我确实自己写不出,写下面代码的时候对一下uDebug,不过我没有看作者代码了(早就看 ...

  4. 计算机图形学E4——OpenGL 区域种子填充

    其他计算机图形学实验见 链接 系统递归栈太慢了,用stack或者queue会好一点,本质一样,都是bfs //DFS 系统递归栈//#include<iostream> //#includ ...

  5. 种子点生长算法(上)——二维种子点生长

    本文只用作笔记,方便日后查阅. 种子点生长算法上--二维种子点生长 下文提到的种子点生长算法,包括泛洪法,扫描线法,区段法三种.文本先从最简单的泛洪法入手介绍种子点生长算法的相关概念.之后进一步讨论了 ...

  6. 种子生长相关算法实现

    下文提到的种子点生长算法,包括泛洪法,扫描线法,区段法三种.文本先从最简单的泛洪法入手介绍种子点生长算法的相关概念.之后进一步讨论了扫描线法和区段法,同时提供了实验数据验证其中的一些结论.本文按照如下 ...

  7. 连通域分析之种子填充法

    一.连通域 需要了解连通域和两遍扫描法的可以看连通域分析之两遍扫描法(Two-Pass)这篇博文.我在里面已经介绍过了连通域的两种定义,这里就不再介绍.在此文中仍以4-邻域为例. 二.种子填充(区域填 ...

  8. 边缘检测、Hough变换、轮廓提取、种子填充、轮廓跟踪

    转自:http://blog.sina.com.cn/s/blog_6c083cdd0100nm4s.html 7.1 边沿检测 我们给出一个模板 和一幅图象 .不难发现原图中左边暗,右边亮,中间存在 ...

  9. 对象是否要被回收(引用计数和可达性分析算法)

    java堆和方法区主要存放各种类型的对象(方法区中也存储一些静态变量和全局常量等信息),那么我们在使用GC对其进行回收的时候首先要考虑的就是如何判断一个对象是否应该被回收.也就是要判断一个对象是否还有 ...

最新文章

  1. vue+vant使用图片预览功能ImagePreview的问题
  2. 让Keil生成汇编文件、bin文件
  3. PyCharm简单使用介绍及注意事项
  4. java 扩展数据类型_java数据类型及其拓展
  5. QT中border-image的解释
  6. Java-IO操作性能对比
  7. 云服务器功能检验方法
  8. Python shift()
  9. JAVA基础——循环结构(while)
  10. 360安全卫士推出“极速版”:永久免费、无弹窗广告!
  11. 软件工程之美学习笔记二十五 24 | 技术债务:是继续修修补补凑合着用,还是推翻重来?
  12. jQWidgets的TreeGrid 心得:
  13. php java扩展模块_php扩展模块装安装
  14. 我妹妹成了我的女儿——难道我真的中年大叔了?
  15. Excel引用函数(1):FORMULATEXT,取得单元格公式内容
  16. 我慌了!我妈从床底掏出了我珍藏多年的小本本-----JAVA_Lambda表达式(笔记)
  17. 干货,看微信小程序后台用户数据如何演变和递增
  18. 蓝桥杯知识点总结C++ B组
  19. 企业网盘的优势到底在哪里?
  20. PP.io的三个阶段,“强中心”——“弱中心”——“去中心”

热门文章

  1. jQuery获取兄弟元素的各种方法总结
  2. java 判断两个日期时间/两个时间戳之间相隔多少天,也可用于获取从1970年以来到某个时间之间相隔多少天
  3. Mysql中索引的最左前缀原则图文剖析(全)
  4. 【洛谷题解】B2050 三角形判断
  5. IntelliJ IDEA字体大小怎么调
  6. 课堂练习12 继承与多态
  7. 新应用——养老院管理应用,信息化的多功能管理应用
  8. 【iOS】FMDB封装,查询自动mapping
  9. Cocos Creater 学习笔记(一)
  10. 电商在线订单分析与可视化