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

来源:互联网 发布:现货原油分析软件 编辑:程序博客网 时间:2024/05/29 09:46

原题地址

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;}
0 0
原创粉丝点击