《算法竞赛入门经典(第2版)》 习题3-6 纵横字谜的答案(Crossword Answers, ACM/ICPC World Finals 1994, UVa232)

《算法竞赛入门经典(第2版)》 习题3-6 纵横字谜的答案(Crossword Answers, ACM/ICPC World Finals 1994, UVa232)

输入一个r行c列(1<=r,c<=10)的网格,黑格用“*”表示,每个白格都填有一个字母。如果一个白格的左边相邻位置或者上边相邻位置没有白格(可能是黑格,也可能出了网格边界),则称这个白格是一个起始格。首先把所有起始格按照从上到下、从左到右的顺序编号为1,2,3,…,如图3-7所示。接下来要找出所有横向单词(Across)。这些单词必须从一个起始格开始,向右延伸到一个黑格的左边或者整个网格的最右列。最后找出所有竖向单词(Down)。这些单词必须从一个起始格开始,向下延伸到一个黑格的上边或者整个网格的最下行。
在这里插入图片描述

输入

每一个字谜网格的输入数据第1行是两个整数r和c,(1 ≤ r ≤ 10 且 1 ≤ c ≤ 10),r是网格的行数,c是网格的列数。接下来是r行字符,每行的字符都有c个,这些字符描述了网格的构成。这些字符或者是字母,或者是用来表示黑格的’*‘号。全部输入的最后是单独的一行,仅包含一个数字’0’。【注意:输入的不同网格之间没有其它内容分隔】

示例输入

2 2
AT
*O
6 7
AIM*DEN
*ME*ONE
UPON*TO
SO*ERIN
*SA*OR*
IES*DEA
0

示例输出

puzzle #1:
Across
1.AT
3.O
Down
1.A
2.TO
puzzle #2:
Across
1.AIM
4.DEN
7.ME
8.ONE
9.UPON
11.TO
12.SO
13.ERIN
15.SA
17.OR
18.IES
19.DEA
Down
1.A
2.IMPOSE
3.MEO
4.DO
5.ENTIRE
6.NEON
9.US
10.NE
14.ROD
16.AS
18.I
20.A

分析

这又是一个模拟题,只要照着题目描述的做即可。值得注意的是,每次准备读入一个网格的数据时,一定要将网格数组清零、起始格数据清零、起始格数量清零,但是不要将网格数量清零。==清零,重要。==然后,就可以愉快的开始读入一个网格的数据了。稳妥起见,可以先读一个r,如果它是0,则结束程序,如果不是0,继续读入c。
接下来,就要逐个记录起始格。可以将第i个起始格的x、y坐标保存在x[i]、y[i]这两个数组中。如果你之前建立网格数组的时候建得比较大,且全部置0了,然后从下标1开始存储——那么现在判断起始格就无需担心数组越界问题,只要一个白格的左边或上边不是白格,就可以记录起始格了。
最后,就要分别输出横向与竖向单词了。输出完毕,不要忘记读取下一个r哟!

代码

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

char a[12][12]; // 存储一个网格的数据
int x[120]; // 存储一个起始格的x坐标,x[1]是第1个起始格的x坐标
int y[120]; // 存储一个起始格的y坐标,y[1]是第1个起始格的y坐标
int r, c, tot=0, heads; // tot计数器存储网格的个数, heads计数器存储起始格的个数

int main()
{
	scanf("%d", &r); // 读入r,或结束标记0
	while(r!=0) // 如果不是0,则继续
	{
		memset(a,0,12*12); // 网格数据清零
		memset(x,0,120); // 起始格数据清零
		memset(y,0,120); // 起始格数据清零
		heads = 0; // 起始格数据清零
		scanf("%d", &c); // 读入c
		tot++;
		printf("\npuzzle #%d\n", tot); // 输出一个网格的抬头(一个空行,然后是编号)
		//-----------------开始输入一个r行c列的网格内部的数据
		char in;
		int count = 0, i=1, j=1; // 一个网格中的元素计数count,i和j是当前输入的元素在网格中的位置
		while(count<r*c) // 输入一个网格的总共r*c个元素
		{
			in = getchar(); // 读入一个字符
			if((in>='A' && in<='Z') || in=='*'){ // 如果输入的是大写字母或*号,
				a[i][j] = in; // 则将输入字符存储到相应位置(i,j)
				count++;
				j++; // 列坐标增加
				if(j>c) j=j%c; // 列坐标防止超出范围
			}
			else if(in=='\n' && count>0) i++; // 如果接收到了换行符,则行坐标增加,为防止输入流中多余换行符的干扰,加一个count判断
		} 
		//------------------输入网格内部数据完毕
		
		//------------------开始统计并记录起始格
		for(i=1; i<=r; i++){
			for(j=1; j<=c; j++)
				// 如果一个白格左边或上边相邻位置没有白格(是黑格或出了边界),那么这是一个起始格
				if(a[i][j]!='*' && (a[i-1][j]==0 || a[i-1][j]=='*' || a[i][j-1]==0 || a[i][j-1]=='*'))
				{
					heads++; // 起始格数量加1
					x[heads] = i; // 记录起始格坐标
					y[heads] = j;
				}
		}
		//-----------------起始格统计记录完毕
		
		//-----------------开始输出横向单词
		printf("Across\n");
		for(i=1;i<=heads;i++)
		{
			if(a[x[i]][y[i]-1]==0 || a[x[i]][y[i]-1]=='*'){ // 如果这是一个向右的起始格,则输出横向单词
				j = y[i];
				printf("%3d.", i);
				while(a[x[i]][j]!='*' && a[x[i]][j]!=0)
					printf("%c", a[x[i]][j++]);
				printf("\n");
			}
		}
		//-----------------横向单词输出完毕
		
		//-----------------开始输出纵向单词
		printf("Down\n");
		for(i=1;i<=heads;i++)
		{
			if(a[x[i]-1][y[i]]==0 || a[x[i]-1][y[i]]=='*'){ // 如果这是一个向下的起始格,则输出横向单词
				j = x[i];
				printf("%3d.", i);
				while(a[j][y[i]]!='*' && a[j][y[i]]!=0)
					printf("%c", a[j++][y[i]]);
				printf("\n");
			}
		}
		//-----------------纵向单词输出完毕
		
		scanf("%d", &r); // 读入下一个网格的r,或结束标记0
	}
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值