6 12_ancient_messages_uva1103 - nuaazdh/acm GitHub Wiki
##例题6-12 古代象形符号(Ancient Messages UVa1103)
###问题
给定5个象形文字的图案,然后要求根据输入的一个图案,输出图案中包含的象形字符(字母序输出)。输入的第一行为两个正整数H
和W
,表示图像的高度和宽度,后面的H
行十六进制数表示图像内容,白色像素点为0
,黑色像素点为1
。输入以 0 0
结束。
###分析
乍一看不知道何从下手,然后根据给定的几个符号,发现了每个符号的特征:即任意两个符号的连通单元的个数不同,因此可以求一个图像的连通单元的个数来唯一确定该符号。如何求一个图像连通单元的个数呢?
联想上一题的种子填充,我们可以转向求连在白色格的数目。好了,已经找到如何确定一个符号的方法,那么一个图像中一共多少个符号?简单,求黑色格子的连通数目即可。
如何区分内部的白色和背景白色?开始想到的是用一个数组,记录黑色DFS过程中H
和W
的范围,在这个范围内统计白色,后来感觉太复杂。因为题目保证图案不触及边,所以直接来个把背景色置为非0和非1的即可。
###code in C++
#include <stdio.h>
#include <string.h>
#include <map>
#define MAX_HEIGHT (210)
#define MAX_WIDTH (60*4)
char map[MAX_HEIGHT][MAX_WIDTH];
char visit[MAX_HEIGHT][MAX_WIDTH];
char line[MAX_HEIGHT];
int dr[] = {-1, 0, 1, 0}, dc[] = {0, -1, 0, 1};
int height, width;
char dict[] = "WAKJSD";
int hex2dec(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
} else if (c >= 'a' && c <= 'f') {
return 10 + c - 'a';
} else {
return 10 + c - 'A';
}
}
int is_visit(int i, int j) {
return (visit[i][j] == 1);
}
int is_valid_pos(int i, int j) {
return (i >= 0 && i < height && j >= 0 && j < width);
}
void print_map(int h, int w) {
int i, j;
for (i = 0; i < h; ++i) {
for (j = 0; j < w; ++j) {
printf("%c", map[i][j]);
}
printf("\n");
}
printf("\n");
}
void dfs(int i, int j, char find, char set) {
int di;
if (!is_valid_pos(i, j) || map[i][j] != find)
return;
map[i][j] = set;
visit[i][j] = 1;
for (di = 0; di < 4; ++di) {
if (map[i + dr[di]][j + dc[di]] == find && !is_visit(i + dr[di], j + dc[di])) {
dfs(i + dr[di], j + dc[di], find, set);
}
}
}
void dfs_character(int i, int j, int &hole) {
int di;
if (!is_valid_pos(i, j) || is_visit(i, j))
return;
visit[i][j] = 1;
for (di = 0; di < 4; ++di) {
if (map[i + dr[di]][j + dc[di]] == '0' && !is_visit(i + dr[di], j + dc[di])) {
++hole;
dfs(i + dr[di], j + dc[di], '0', ' ');
// print_map(height, width);
}
if (map[i + dr[di]][j + dc[di]] == '1' && !is_visit(i + dr[di], j + dc[di])) {
dfs_character(i + dr[di], j + dc[di], hole);
}
}
}
void find_character_count(int kcase) {
int i, j;
int hole;
std::map<char, int> result;
for (j = 0; j < width; ++j) {
dfs(0, j, '0', ' '); // clear backgroud
dfs(height - 1, j, '0', ' '); // clear backgroud
}
for(i=0;i<height;++i){
dfs(i, 0 , '0', ' '); // clear backgroud
dfs(i, width-1, '0', ' '); // clear backgroud
}
// print_map(height, width);
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
hole = 0;
if (map[i][j] == '1' && !is_visit(i, j)) {
dfs_character(i, j, hole);
if (result.count(dict[hole])) {
++result[dict[hole]];
} else {
result[dict[hole]] = 1;
}
}
}
}
printf("Case %d: ", kcase);
for (std::map<char, int>::iterator it = result.begin(); it != result.end(); ++it) {
for (i = 0; i < it->second; ++i)
printf("%c", it->first);
}
printf("\n");
}
int main() {
int h, w, i, j, num, kcase = 0;
while (scanf("%d%d", &h, &w) && h) {
memset(map, 0, sizeof(map));
memset(visit, 0, sizeof(visit));
height = h;
width = 4 * w;
for (i = 0; i < h; ++i) {
scanf("%s", line);
for (j = 0; j < w; ++j) {
num = hex2dec(line[j]);
map[i][4 * j] = (num & (1 << 3)) ? '1' : '0';
map[i][4 * j + 1] = (num & (1 << 2)) ? '1' : '0';
map[i][4 * j + 2] = (num & (1 << 1)) ? '1' : '0';
map[i][4 * j + 3] = (num & 0x01) ? '1' : '0';
}
}
// print_map(height,width);
// printf("Case %d:\n", ++kcase);
find_character_count(++kcase);
}
return 0;
}
###点评
- 注意审题,题中有多个条件,其中一个说明,对角的黑色像素是不属于同一个图形的,所以方向只有4个,而不是8个;
- 清除背景的方法有点 ugly;
- 执行时间和第20名相同,
0.013
,考虑优化下
###改进
#include <stdio.h>
#include <string.h>
#include <map>
#define MAX_HEIGHT (210)
#define MAX_WIDTH (60*4)
char map[MAX_HEIGHT][MAX_WIDTH];
char line[MAX_HEIGHT];
int dr[] = {-1, 0, 1, 0}, dc[] = {0, -1, 0, 1};
int height, width;
char dict[] = "WAKJSD";
int hex2dec(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
} else if (c >= 'a' && c <= 'f') {
return 10 + c - 'a';
} else {
return 10 + c - 'A';
}
}
int is_valid_pos(int i, int j) {
return (i >= 0 && i < height && j >= 0 && j < width);
}
void print_map(int h, int w) {
int i, j;
for (i = 0; i < h; ++i) {
for (j = 0; j < w; ++j) {
printf("%c", map[i][j]);
}
printf("\n");
}
printf("\n");
}
void dfs(int i, int j, char find, char set) {
int di;
map[i][j] = set;
for (di = 0; di < 4; ++di) {
if (is_valid_pos(i + dr[di], j + dc[di]) && map[i + dr[di]][j + dc[di]] == find) {
dfs(i + dr[di], j + dc[di], find, set);
}
}
}
void dfs_character(int i, int j, int &hole) {
int di;
map[i][j] = ' ';
for (di = 0; di < 4; ++di) {
if (is_valid_pos(i + dr[di], j + dc[di]) && map[i + dr[di]][j + dc[di]] == '0') {
++hole;
dfs(i + dr[di], j + dc[di], '0', ' ');
}
if (is_valid_pos(i + dr[di], j + dc[di]) && map[i + dr[di]][j + dc[di]] == '1') {
dfs_character(i + dr[di], j + dc[di], hole);
}
}
}
void find_character_count(int kcase) {
int i, j;
int hole;
std::map<char, int> result;
// clear backgroud
for (j = 0; j < width; ++j) {
if (map[0][j] == '0') dfs(0, j, '0', ' ');
if (map[height - 1][j] == '0') dfs(height - 1, j, '0', ' ');
}
for (i = 0; i < height; ++i) {
if (map[i][0] == '0') dfs(i, 0, '0', ' ');
if (map[i][width - 1] == '0') dfs(i, width - 1, '0', ' ');
}
// find the symbol
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
hole = 0;
if (map[i][j] == '1') {
dfs_character(i, j, hole);
if (result.count(dict[hole])) {
++result[dict[hole]];
} else {
result[dict[hole]] = 1;
}
}
}
}
printf("Case %d: ", kcase);
for (std::map<char, int>::iterator it = result.begin(); it != result.end(); ++it) {
for (i = 0; i < it->second; ++i)
printf("%c", it->first);
}
printf("\n");
}
int main() {
int h, w, i, j, num, kcase = 0;
while (scanf("%d%d", &h, &w) && h) {
memset(map, 0, sizeof(map));
height = h;
width = 4 * w;
for (i = 0; i < h; ++i) {
scanf("%s", line);
for (j = 0; j < w; ++j) {
num = hex2dec(line[j]);
map[i][4 * j] = (num & (1 << 3)) ? '1' : '0';
map[i][4 * j + 1] = (num & (1 << 2)) ? '1' : '0';
map[i][4 * j + 2] = (num & (1 << 1)) ? '1' : '0';
map[i][4 * j + 3] = (num & 0x01) ? '1' : '0';
}
}
// print_map(height,width);
find_character_count(++kcase);
}
return 0;
}
###说明:
- 去掉了 visit, 因为背景色设置为空格,图案遍历以后也设置为空格,数完空洞后也设置为空格,这样不需要再记录那些点访问过;
- 去掉了 is_valid_pos 多处调用,放到if里面,这样不用进函数来判断,减少函数调用次数;
- 优化的结果执行时间还是
0.013
,╮(╯▽╰)╭