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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Africa_South/article/details/102511693

原题:
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
00

Output:
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 DEBUG

const 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,默认为-1
	image[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; // 暂时标记成背景,也可以标记成其他元素,比如文字对应的id
	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] == 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 DEBUG
		printf("输入的图像\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 DEBUG
		printf("背景填充后\n");
		printMap();
#endif
		for (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;
}

猜你喜欢

转载自blog.csdn.net/Africa_South/article/details/102511693
今日推荐