UVa 232 Crossword Answers(枚举+输入输出)

原题地址

https://vjudge.net/problem/UVA-232

题意:输入r行c列的网格,黑格用 ‘*’ 表示, 每个白格上都填有一个字母。如果一个白格的左邻或上邻位置没有白格(黑格或越界),则称该白格是一个起始格。
首先将所有起始格按照从上到下,从左到右的顺序编号1,2,3……
接下来找出所有的横向单词(从一个无左邻的起始格开始,向右延伸至黑格或边界),再找出所有的纵向单词(从一个无上邻的起始格开始,向下延伸至白格或边界)。按要求输出这些单词。
r行c列

解题思路

本题是《算法竞赛入门经典》的习题3-6,是比较基本的枚举题目。

遍历每个格子,首先判断是否满足起始格的要求,如果满足再将以其为开端的横向单词、纵向单词(分别无左邻、上邻)的位置存到across、down结构体数组中。最后控制输出格式。

值得注意的点:

  • 依然和输入字符相关,由于scanf依次读入了row、col值,所以读完col后会多出来一个换行,必须用getchar()吞掉这个回车,不然会被当成数组元素读入。
  • 如果题目要求两个连续输入的输出之间有一个空行(Separate output for successive input puzzles by a blank line.)那么不要每个测试之后都多输出一个换行,而是在第一个以后的测试结果输出前打入一个空行,这样可以保证结束标志0后没有换行。
  • 结构体里存的是这个单词的起始坐标(二元)和终止坐标(一元,要么横着,要么竖着),直接vector存string也是可以的。
  • 小心输出格式,一位编号前输出2个空格,两位编号前输出1个空格。

AC代码

#include <iostream>
#include <stdio.h>
using namespace std;

typedef struct word
{
    int num, si, sj, e; //标号、行号、列号、终止位置后一格
}WORD;

char puzzle[15][15];
WORD across[1000], down[1000];
int a,b;

bool isEligible(int i, int j) //判断是否合法的开始元
{
    if (puzzle[i][j] == '*') return false;
    else if (!i || !j || puzzle[i-1][j] == '*' || puzzle[i][j-1] == '*')
        return true;
    return false;
}

/*
void printPuzzle(int r, int c) //检查读入
{
    for (int i = 0; i < r; ++i)
    {
        for (int j = 0; j < c; ++j)
            printf("%c ", puzzle[i][j]);
        printf("\n");
    }
}*/

int main()
{
    int row, col, kase = 0;
    while (~scanf("%d", &row) && row) //终止条件为row=0
    {
        scanf("%d", &col);
        getchar(); //吞掉col之后的回车,防止被读为数组元素
        kase++;
        for (int i = 0; i < row; ++i)
        {
            for (int j = 0; j < col; ++j)
                scanf("%c", &puzzle[i][j]);
            getchar(); //逐个读字符后记得吞掉回车
        }
        //printPuzzle(row, col); //检查读入
        a = b = 0;
        int begin_num = 0;
        for (int i = 0; i < row; ++i)
        {
            for (int j = 0; j < col; ++j)
            {
                if (isEligible(i, j)) //是开始元
                {
                    begin_num++; //标号+1
                    int k;
                    if (!j || puzzle[i][j-1] == '*') //可以作为横向开始元素
                    {
                        k = j+1; //检查其右
                        while (k < col && puzzle[i][k] != '*')
                            k++;
                        //存入across结构体数组
                        across[a].num = begin_num;
                        across[a].si = i, across[a].sj = j;
                        across[a].e = k; //结束位置后一个
                        a++;
                    }
                    if (!i || puzzle[i-1][j] == '*') //可以作为纵向开始元素
                    {
                        k = i+1; //检查其下
                        while (k < row && puzzle[k][j] != '*')
                            k++;
                        //存入across结构体数组
                        down[b].num = begin_num;
                        down[b].si = i, down[b].sj = j;
                        down[b].e = k; //结束位置后一个
                        b++;
                    }
                }//标记元素处理结束
            }//遍历行内结束
        }//遍历每一行结束

        if(kase > 1) printf("\n"); //分隔puzzle的输出
        printf("puzzle #%d:\n", kase);

        int i,j,r,c,ending;
        //输出以across的每个字符开始的横向词
        printf("Across\n");
        for (i = 0; i<a; ++i)
        {
            if (across[i].num < 10) //控制空格
                printf("  ");
            else if (across[i].num < 100)
                printf(" ");
            printf("%d.", across[i].num);
            r = across[i].si; //固定行
            ending = across[i].e;
            for (j = across[i].sj; j < ending; ++j)
                putchar(puzzle[r][j]);
            printf("\n");
        }

        //输出以down的每个字符开始的纵向词
        printf("Down\n");
        for (i = 0; i<b; ++i)
        {
            if (down[i].num < 10) //控制空格
                printf("  ");
            else if (down[i].num < 100)
                printf(" ");
            printf("%d.", down[i].num);
            c = down[i].sj; //固定列
            ending = down[i].e;
            for (j = down[i].si; j < ending; ++j)
                putchar(puzzle[j][c]);
            printf("\n");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值