例题6-13 古代象形符号 UVa1103

该博客介绍了如何解决UVa1103问题,涉及将16进制编码转为二进制字符串,并通过DFS算法识别图像中的象形符号。关键在于标记图案边界、黑点及统计洞的个数。提供了详细的解题思路和代码注释,并附带测试数据。
摘要由CSDN通过智能技术生成

1.题目描述:点击打开链接

2.解题思路:本题给出了一张图片的16进制的编码,要求找出这张图片中出现的符号。解码成二进制字符串后,实际上就是用普通的dfs解决了,不过如何进行dfs是本题的关键。

根据题意,每个符号的不同之处在于“洞”的个数不同,这就是它们的特征值,因此只要能够找出每个图形的洞的个数,即可确定图案是谁了。为了能够更好地进行dfs,我们需要先将图案外侧的所有0给标记掉,这里用字符‘-’来处理。然后再扫描这张图,如果遇到字符‘1’,说明找到了一个黑点,从它入手找到整个图案,用‘*’来标记黑点;如果在寻找过程中遇到了‘0’,说明找到了一个洞,对它也进行上述的处理,同时更新找到的洞的个数。

综上所述,我们相当于要进行三种不同的dfs。第一种是用来处理边界;第二种是标记图案的黑点;第三种是统计图案中内部的洞的个数。这里有一个技巧:给dfs传递一个控制变量isp,由它来控制三种不同的类型。具体过程详见代码注释。

由于本题没有给出具体的测试样例,因此以下附上找到的测试数据供测试。

3.代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

#define N 1024
int H, W, ant, black;
char*ch = "WAKJSD";
string s, res, ans[N];
const char*table[] = { "0000", "0001", "0010", "0011",
"0100", "0101", "0110", "0111", "1000", "1001", "1010",
"1011", "1100", "1101", "1110", "1111" };
void clear()
{
	for (int i = 0; i < N; i++)
		ans[i].clear();
}
void dfs(int r, int c, int isp)//isp为1时标记边界;2标记黑点;3标记所有的洞
{
	if (r < 0 || r >= H || c < 0 || c >= W * 4)return;
	if ((isp == 1 || isp == 3) && ans[r][c] != '0')return;
	if (isp == 2 && ans[r][c] != '1'&&ans[r][c] != '0')return;
	if (isp == 1)ans[r][c] = '-';
	if (isp == 2 && ans[r][c] == '0')
	{
		black++;
		dfs(r, c, 3);
	}
	if (isp == 2 && ans[r][c] == '1')
		ans[r][c] = '*';
	if (isp == 3)ans[r][c] = '-';
	dfs(r + 1, c, isp);
	dfs(r, c + 1, isp);
	dfs(r - 1, c, isp);
	dfs(r, c - 1, isp);
}
int main()
{
	//freopen("t.txt", "r", stdin);
	int rnd = 1;
	while (~scanf("%d%d", &H, &W) && (H || W))
	{
		ant = 0;
		res.clear();
		clear();
		for (int i = 0; i < H; i++)
		{
			cin >> s;
			for (int j = 0; j < W; j++)
			{
				int t;
				if (isdigit(s[j]))
					t = s[j] - '0';
				else t = 10 + s[j] - 'a';
				ans[i] += table[t];
			}
		}
		for (int i = 0; i < H; i++)//处理左右两个边界
		{
			if (ans[i][0] == '0')dfs(i, 0, 1);
			if (ans[i][W * 4 - 1] == '0')dfs(i, W * 4 - 1, 1);
		}
		for (int i = 0; i < W * 4; i++)//处理上下两个边界
		{
			if (ans[0][i] == '0')dfs(0, i, 1);
			if (ans[H - 1][i] == '0')dfs(H - 1, i, 1);
		}
		for (int i = 0; i < H;i++)
		for (int j = 0; j < W * 4;j++)
		if (ans[i][j] == '1')//找到一个符号
		{
			black = 0;
			dfs(i, j, 2);
			res += ch[black];
		}
		sort(res.begin(), res.end());//最后要按照字典序输出
		printf("Case %d: ", rnd++);
		cout << res << endl;
	}
	return 0;
}

4.测试数据:

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
2
3
4
5
6
7
8
9
a
b
c
d
e
f
9 2
00
7e
42
7e
42
7e
42
7e
00
43 2
00
7e
00
7e
42
7e
42
7e
42
7e
00
7e
42
7e
00
7e
42
7e
42
7e
00
7e
42
7e
42
7e
42
7e
42
7e
00
7e
42
7e
42
7e
42
7e
42
7e
42
7e
00
200 50
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值