【OJ-UVa232】

再入刷题。不似当年那么自大了,放空自己,从基础开始。果然,当年觉得超简单超Low的基础真正实践起来并不容易,当年自大犯的错,不仅坑了当年的自己,还坑到现在。

人生的路啊,从来都是一步一步的,你跳过的坑,迟早还要栽进去。不如趁年轻,早早的埋了这些坑。

刷题之路,从刘汝佳的《算法竞赛入门经典》第二版开始。另外强烈建议,每一步都打桩输出中间结果,省的DEBUG时很痛苦,很费时。说实话,书中说的gdb这个调试工具很好用,我是体验不出来。

来看UVa232吧。

题目解析

说到题目,英文四六级水平要有。感觉此题像是字谜题的简化版。

  1. 先对合法单词首字母的按序编号。该字母满足如下条件,则它就是合法的单词首字母:
    1. 左侧是边界,或者 *
    2. 上侧是边界,或者 *
  2. 判断是Across横向还是down竖向单词
    1. Across单词:左侧是边界,或者 *
    2. Down单词  :上侧是边界,或者 * 
    3. 两个条件都满足,既是Across又是Down
  3. 最后是输出单词
    1. 先输出 Across单词
    2. 若 该格是 单词首字母,且 是 Across单词,则
      1. 认定该格为 单词begin
      2. 往右遍历,直到边界或者遇到*
      3. 当前就是  单词end 
    3. 输出 begin到end格的字母。
    4. 再输出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;
}
发布了58 篇原创文章 · 获赞 44 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qilei2010/article/details/88627481