再入刷题。不似当年那么自大了,放空自己,从基础开始。果然,当年觉得超简单超Low的基础真正实践起来并不容易,当年自大犯的错,不仅坑了当年的自己,还坑到现在。
人生的路啊,从来都是一步一步的,你跳过的坑,迟早还要栽进去。不如趁年轻,早早的埋了这些坑。
刷题之路,从刘汝佳的《算法竞赛入门经典》第二版开始。另外强烈建议,每一步都打桩输出中间结果,省的DEBUG时很痛苦,很费时。说实话,书中说的gdb这个调试工具很好用,我是体验不出来。
来看UVa232吧。
题目解析
说到题目,英文四六级水平要有。感觉此题像是字谜题的简化版。
- 先对合法单词首字母的按序编号。该字母满足如下条件,则它就是合法的单词首字母:
- 左侧是边界,或者 *
- 上侧是边界,或者 *
- 判断是Across横向还是down竖向单词
- Across单词:左侧是边界,或者 *
- Down单词 :上侧是边界,或者 *
- 两个条件都满足,既是Across又是Down
- 最后是输出单词
- 先输出 Across单词
- 若 该格是 单词首字母,且 是 Across单词,则
- 认定该格为 单词begin
- 往右遍历,直到边界或者遇到*
- 当前就是 单词end
- 输出 begin到end格的字母。
- 再输出Down单词,同上。
个人总结
前期,代码我觉得思路清晰最重要,不用过多使用优化过后的代码。很多 ++ 放到 while 中,对于新手很容易引起混乱和莫名其妙的错误,很难调试。
本题数据量很小,可放心使用多个数组。我用了三个数组,且不管网上那些巧妙的解法,目前思路清晰最重要。
解题中,踩过 memset 函数的坑(前面单独拎出来写了一篇博客),踩过 scanf 的坑,写在注释里了。
AC代码
下面是我的原创AC代码,C语言编写。中间有部分调试代码,用于观察中间变量。只需要把 #define LOCAL_LOG 注释去掉即可看到中间变量的输出。
// 3-6.c
//当我们输入数据,在按下回车键前会把数据储存在缓冲区,
//按下回车键后,会把数据以及换行符(\n)一起传送到标准输入流(stdin)中,
//注意:scanf("%c") 会读取空格、制表符、换行符
//注意:scanf() 之后用 getchar() 吞掉后面的换行符 空格 制表符等
//memset函数以字节为单位进行赋值
//int a[4]; memset(a, 1, sizeof(a));
//a[0] = 0x01010101 而非 1
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
// #define LOCAL
// #define LOCAL_LOG
char grid[15][15]; //存储字母
int word[15][15]; //0 表示word首字母,其它表示序号
int across[15][15];//2:down,5:across,10 :both
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout)
#endif
int r = 0, c = 0, i = 0, j = 0, puzzle = 0;
while(scanf("%d%d", &r, &c) == 2 && r != 0){
getchar(); //吞掉换行符
//init
memset(grid, 0, sizeof(grid));
memset(word, 0, sizeof(word));
for (i = 0; i < r; ++i)
for (j = 0; j < c; ++j)
across[i][j] = 1;
int seq = 0;
for (i = 0; i < r; ++i)
scanf("%s", grid[i]);
//遍历
for (i = 0; i < r; ++i)
{
for (j = 0; j < c; ++j)
{
//起始字符编号
if (grid[i][j] != '*'
&&
(i-1<0 || j-1<0
|| (i-1>=0 && grid[i-1][j] == '*')
|| (j-1>=0 && grid[i][j-1] == '*')))
{
word[i][j] = ++ seq;
//判断Across Down
if (i-1<0 || (i-1>=0 && grid[i-1][j] == '*'))
{
across[i][j] *=2; //down
}
if( j-1<0 || (j-1>=0 && grid[i][j-1] == '*'))
{
across[i][j] *=5; //across
}
}
}
}
#ifdef LOCAL_LOG
printf("原数据\n");
for (i = 0; i < r; ++i)
{
for (j = 0; j < c; ++j){
printf("%c", grid[i][j]);
}
printf("\n");
}
printf("Word数据\n");
for (i = 0; i < r; ++i)
{
for (j = 0; j < c; ++j){
printf("%3d", word[i][j]);
}
printf("\n");
}
printf("Across数据\n");
for (i = 0; i < r; ++i)
{
for (j = 0; j < c; ++j){
printf("%3d ", across[i][j]);
}
printf("\n");
}
#endif
// char *word;
if (puzzle) printf("\n");
printf("puzzle #%d:\nAcross\n", ++puzzle);
//get begin and end of row
int i = 0, j = 0, k = 0, m = 0;
int begin = 0, end = 0;
for (i = 0; i < r; ++i)
{
for (j = 0; j < c; ++j)
{
if (word[i][j] && across[i][j] >=5 )
{
begin = j;
m = j;
while( m<c && grid[i][m] != '*') ++m ;
end = m;
// printf("being:%d,end:%d\n", begin,end);
printf("%3d.", word[i][begin]);
for (k = begin; k < end; ++k)
{
printf("%c", grid[i][k]);
}
printf("\n");
}
}
}
printf("Down\n");
i = 0, j = 0, k = 0, m = 0;
begin = 0, end = 0;
for (i = 0; i < r; ++i)
{
for (j = 0; j < c; ++j)
{
if (word[i][j] && (across[i][j] ==2 || across[i][j] == 10) )
{
begin = i;
m = i;
while( m<r && grid[m][j] != '*') ++m ;
end = m;
// printf("being:%d,end:%d\n", begin,end);
printf("%3d.", word[begin][j]);
for (k = begin; k < end; ++k)
{
printf("%c", grid[k][j]);
}
printf("\n");
}
}
}
}
return 0;
}